> ## Documentation Index
> Fetch the complete documentation index at: https://docs.levios.app/llms.txt
> Use this file to discover all available pages before exploring further.

# Send carousel messages

> Create an Instagram DM carousel with image cards, URL buttons, and a following message through API v1.

Use `send_carousel` in `configuration.follow_up.actions` to send image cards
in an Instagram DM. Each card has a title and link buttons. A message after the
cards is a separate action in the same sequence.

## Card fields and limits

| Field | Accepted value |
| - | - |
| `type` | `send_carousel`. |
| `delay_seconds` | Required integer from 0 through 86399. |
| `cards` | 1 to 10 cards, in display order. |
| `cards[].title` | Required, 1 to 80 Unicode scalar values. |
| `cards[].subtitle` | Optional, 0 to 80 Unicode scalar values. |
| `cards[].image_url` | Required public HTTP(S) image URL. |
| `cards[].buttons` | 1 to 3 buttons, in display order. |
| `cards[].buttons[].type` | `url`. |
| `cards[].buttons[].title` | Required, 1 to 20 Unicode scalar values. |
| `cards[].buttons[].url` | Required HTTP(S) destination URL. |

Card and button titles must not have leading or trailing whitespace. Character
limits count Unicode scalar values, which can differ from JavaScript string
length. Keep URLs valid, including their port and percent encoding.

Use the public `cards` shape. Unknown properties such as `elements` and
`default_action`, or a card button with `type: "postback"`, are rejected.

## Prepare the images

Host each image at a URL that opens without login and keep it available until
delivery. Cards accept images. The dashboard uploader accepts JPG, PNG, and GIF
files up to 8 MiB. REST and MCP accept URLs and have no media upload operation.
Configuration validation does not fetch an image or verify its file size;
a saved configuration does not prove that Instagram can retrieve the media.

## Create a complete automation

This example sends an opening DM when a comment matches the keyword. Clicking
its `start_follow_up` button begins the carousel sequence. Sending the opening
alone does not start it. Card URL clicks do not resume the sequence or refresh
the 24-hour messaging window.

Save this complete request body as `carousel.json`. Replace the example account
UUID with an accessible account ID and every example URL with your own URL.
The messages, keyword, five-second pause, disabled public replies, and cooldown
are illustrative choices. `status: "draft"` saves the example for review.

```json theme={null}
{
  "account_id": "00000000-0000-4000-8000-000000000001",
  "name": "Collection request",
  "status": "draft",
  "configuration": {
    "contact_filter": "anyone",
    "trigger": {
      "type": "comment",
      "publication": {
        "mode": "all"
      },
      "keywords": {
        "mode": "specific",
        "match_mode": "whole_word",
        "values": [
          "CATALOG"
        ]
      }
    },
    "opening": {
      "public_reply": {
        "enabled": false
      },
      "direct_message": {
        "delay_seconds": 0,
        "message": {
          "text": "Want to see the collection?",
          "buttons": [
            {
              "type": "start_follow_up",
              "title": "Show me"
            }
          ]
        }
      }
    },
    "follow_up": {
      "actions": [
        {
          "type": "send_carousel",
          "delay_seconds": 0,
          "cards": [
            {
              "title": "Activity kit",
              "subtitle": "Creative activities for the weekend",
              "image_url": "https://example.com/activity-kit.jpg",
              "buttons": [
                {
                  "type": "url",
                  "title": "View product",
                  "url": "https://example.com/product"
                },
                {
                  "type": "url",
                  "title": "See details",
                  "url": "https://example.com/details"
                },
                {
                  "type": "url",
                  "title": "Visit store",
                  "url": "https://example.com/store"
                }
              ]
            }
          ]
        },
        {
          "type": "send_message",
          "delay_seconds": 5,
          "text": "Find more ideas in our group.",
          "buttons": [
            {
              "type": "url",
              "title": "Join the group",
              "url": "https://example.com/group"
            }
          ]
        },
        {
          "type": "finish"
        }
      ]
    },
    "extras": {
      "cooldown": {
        "mode": "none"
      }
    }
  }
}
```

Send the file with a key that has `automations:write` and account access:

```bash theme={null}
curl --request POST \
  --url 'https://levios.app/api/v1/automations' \
  --header "Authorization: Bearer ${LEVIOS_API_KEY}" \
  --header 'Content-Type: application/json' \
  --data-binary @carousel.json
```

Creating with `status: "live"` also requires `automations:activate` and account
eligibility. See [Create an automation](/api/v1/automations/create) for the
response and uncertain-creation retry rules. Do not automatically repeat a
creation whose outcome is unknown.

## Schedule the following message

The `send_message` action is separate from the card buttons. Its
`delay_seconds` is relative to the preceding action's successful completion.
The example schedules the group invitation five seconds after the carousel
send succeeds. It does not wait for a card view, link click, or group join.

Configured waits must fit the applicable messaging window. Delays and retries
do not extend the window. Shared account pacing and provider cooldowns can
postpone a send beyond its configured pause. This is separate from the HTTP
API's [rate limits](/guides/rate-limits); creating an automation is not a
promise of immediate delivery or a fixed messages-per-hour quota.

## Read, edit, and handle errors

[Get the automation](/api/v1/automations/get) after writing and check its stored
card order, buttons, following action, and status. When editing, send the full
configuration and a fresh `expected_updated_at` through
[Update an automation](/api/v1/automations/update). Configuration replacement
is not a partial card patch. Follow that endpoint's publication rules for live
automations with unpublished changes.

Invalid fields return `422` with `api_automation_invalid_configuration` and
issues in `error.details.issues`. Check the reported path: too many cards,
a fourth button, an invalid URL, or a missing required delay needs correction.
Preserve unrelated configuration when repairing an issue.

Clients that enumerate follow-up action types must handle `send_carousel` in
both requests and returned configurations. Read the current
[OpenAPI document](/openapi/v1.json) before building an exhaustive decoder.
For the same workflow through an agent, use [Carousels with MCP](/mcp/carousels).
