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

# Create a Creative

> Create a new message creative with offer link placeholders.

Creates a new creative in your account. The message body must contain at least one `{{linkN}}` placeholder, and every placeholder must have a corresponding entry in the `offer_links` array.

## Body Parameters

<ParamField body="name" type="string" required>
  Display name for the creative. Maximum 255 characters.
</ParamField>

<ParamField body="message" type="string" required>
  The message template. Maximum 1600 characters. Must contain at least one `{{linkN}}` placeholder (e.g. `{{link1}}`). Placeholders are replaced with tracked short links at send time.
</ParamField>

<ParamField body="offer_links" type="array" required>
  Array of offer link objects that map to the `{{linkN}}` placeholders in the message. Each placeholder in the message must have a matching entry.

  <Expandable title="Offer link properties">
    <ParamField body="offer_links[].key" type="string" required>
      The placeholder key. Must match a placeholder in the message (e.g. `link1` corresponds to `{{link1}}`).
    </ParamField>

    <ParamField body="offer_links[].offer_id" type="string" required>
      The ID of the offer to associate with this link. Must be a valid 24-character hexadecimal ObjectId, and the offer must exist and belong to your account.
    </ParamField>

    <ParamField body="offer_links[].url" type="string" optional>
      Optional URL override. When provided, this URL is used instead of the offer's default URL.
    </ParamField>

    <ParamField body="offer_links[].url_params" type="object" optional>
      Optional additional query parameters to append to the link URL.
    </ParamField>
  </Expandable>
</ParamField>

<ParamField body="status" type="string" default="active">
  Initial status of the creative. Accepted values: `active`, `paused`.
</ParamField>

<ParamField body="creative_type" type="string" default="automated">
  The type of creative. Accepted values: `automated`, `one_time`, `welcome`.
</ParamField>

<ParamField body="list_control_mode" type="string" default="all">
  List targeting control mode. Accepted values: `all`, `include`, `exclude`.
</ParamField>

<ParamField body="list_control_ids" type="array" optional>
  List IDs (integers) to include or exclude when `list_control_mode` is `include` or `exclude`.
</ParamField>

## Response Fields

<ResponseField name="success" type="boolean">
  Indicates whether the creative was created successfully.
</ResponseField>

<ResponseField name="creative" type="object">
  The full creative object.

  <Expandable title="Creative object properties">
    <ResponseField name="id" type="integer">
      Unique identifier for the creative.
    </ResponseField>

    <ResponseField name="name" type="string">
      Display name of the creative.
    </ResponseField>

    <ResponseField name="message" type="string">
      The message template with `{{linkN}}` placeholders.
    </ResponseField>

    <ResponseField name="offer_links" type="array">
      Array of offer link objects.
    </ResponseField>

    <ResponseField name="offers" type="array">
      Array of offer ID strings referenced by this creative.
    </ResponseField>

    <ResponseField name="status" type="string">
      Current status of the creative.
    </ResponseField>

    <ResponseField name="creative_type" type="string">
      The type of creative.
    </ResponseField>

    <ResponseField name="character_count" type="integer">
      Estimated character count. Link placeholders are estimated as 23 characters each, plus 34 characters of compliance overhead (e.g. opt-out language).
    </ResponseField>

    <ResponseField name="segment_count" type="integer">
      Estimated SMS segment count, encoding-aware. The message is expanded (link placeholders as 23 characters plus 34 characters of compliance overhead) and segmented the way carriers bill it. GSM-7 messages fit 160 septets in a single segment, or 153 septets per part when concatenated; extension-table characters (`^ { } [ ] ~ | € \` and form-feed) cost 2 septets each. If the message contains any non-GSM-7 character (e.g. emoji), UCS-2 encoding applies instead: 70 characters single, 67 per concatenated part.
    </ResponseField>

    <ResponseField name="created_at" type="datetime">
      ISO 8601 timestamp of when the creative was created.
    </ResponseField>

    <ResponseField name="slug" type="string">
      Auto-generated unique slug for the creative.
    </ResponseField>

    <ResponseField name="list_control_mode" type="string">
      List targeting control mode. One of: `all` (default), `include`, `exclude`.
    </ResponseField>

    <ResponseField name="list_control_ids" type="array">
      List IDs used when `list_control_mode` is `include` or `exclude`.
    </ResponseField>
  </Expandable>
</ResponseField>

<Note>
  **Segment calculation**: Each link placeholder is estimated as 23 characters (short link length), plus 34 characters of compliance overhead for required opt-out language. Segmentation is encoding-aware and matches carrier billing. GSM-7 messages fit 160 septets in a single segment, or 153 septets per part when concatenated (extension-table characters such as `€ { } [ ] ~ | ^ \` cost 2 septets each). If the message contains any non-GSM-7 character (e.g. emoji), UCS-2 encoding applies: 70 characters single, 67 per concatenated part.
</Note>

## Examples

<RequestExample>
  ```bash cURL theme={null}
  curl -X POST "https://api.tracklysms.com/api/v2/creatives" \
    -H "X-Api-Key: trk_your_api_key_here" \
    -H "Content-Type: application/json" \
    -d '{
      "name": "Summer Sale Promo",
      "message": "Hot deals just for you! Shop now: {{link1}} Reply STOP to opt out.",
      "offer_links": [
        {
          "key": "link1",
          "offer_id": "665f1a2b3c4d5e6f70819201",
          "url_params": {"sub1": "sms"}
        }
      ],
      "status": "active",
      "creative_type": "automated"
    }'
  ```

  ```python Python theme={null}
  import requests

  response = requests.post(
      "https://api.tracklysms.com/api/v2/creatives",
      headers={
          "X-Api-Key": "trk_your_api_key_here",
          "Content-Type": "application/json"
      },
      json={
          "name": "Summer Sale Promo",
          "message": "Hot deals just for you! Shop now: {{link1}} Reply STOP to opt out.",
          "offer_links": [
              {
                  "key": "link1",
                  "offer_id": "665f1a2b3c4d5e6f70819201",
                  "url_params": {"sub1": "sms"}
              }
          ],
          "status": "active",
          "creative_type": "automated"
      }
  )

  data = response.json()
  print(f"Created creative #{data['creative']['id']}")
  print(f"Segments: {data['creative']['segment_count']}")
  ```

  ```javascript Node.js theme={null}
  const response = await fetch(
    "https://api.tracklysms.com/api/v2/creatives",
    {
      method: "POST",
      headers: {
        "X-Api-Key": "trk_your_api_key_here",
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        name: "Summer Sale Promo",
        message:
          "Hot deals just for you! Shop now: {{link1}} Reply STOP to opt out.",
        offer_links: [
          {
            key: "link1",
            offer_id: "665f1a2b3c4d5e6f70819201",
            url_params: { sub1: "sms" },
          },
        ],
        status: "active",
        creative_type: "automated",
      }),
    }
  );

  const data = await response.json();
  console.log(`Created creative #${data.creative.id}`);
  ```
</RequestExample>

<ResponseExample>
  ```json 201 — Created theme={null}
  {
    "success": true,
    "creative": {
      "id": 101,
      "name": "Summer Sale Promo",
      "message": "Hot deals just for you! Shop now: {{link1}} Reply STOP to opt out.",
      "offer_links": [
        {
          "key": "link1",
          "offer_id": "665f1a2b3c4d5e6f70819201",
          "url_params": {"sub1": "sms"}
        }
      ],
      "offers": ["665f1a2b3c4d5e6f70819201"],
      "status": "active",
      "creative_type": "automated",
      "character_count": 114,
      "segment_count": 1,
      "created_at": "2025-06-10T12:00:00",
      "slug": "cre_summer-sale-promo_a1b2c3",
      "list_control_mode": "all",
      "list_control_ids": []
    }
  }
  ```

  ```json 400 — Validation Error theme={null}
  {
    "error": "message must contain at least one {{linkN}} placeholder",
    "code": "missing_link_placeholder"
  }
  ```

  ```json 400 — Offer Not Found theme={null}
  {
    "error": "Offer not found: 665f1a2b3c4d5e6f70819201",
    "code": "offer_not_found"
  }
  ```

  ```json 401 — Unauthorized theme={null}
  {
    "error": "Invalid credentials",
    "code": "invalid_credentials"
  }
  ```
</ResponseExample>

## Error Codes

| HTTP Status | Error Code                             | Description                                                                                        |
| ----------- | -------------------------------------- | -------------------------------------------------------------------------------------------------- |
| 400         | `missing_name`                         | The `name` field is required.                                                                      |
| 400         | `missing_message`                      | The `message` field is required.                                                                   |
| 400         | `missing_offer_links`                  | The `offer_links` array is required and must not be empty.                                         |
| 400         | `name_too_long`                        | The `name` exceeds 255 characters.                                                                 |
| 400         | `message_too_long`                     | The `message` exceeds 1600 characters.                                                             |
| 400         | `invalid_status`                       | The provided `status` is not `active` or `paused`.                                                 |
| 400         | `invalid_creative_type`                | The provided `creative_type` is not `automated`, `one_time`, or `welcome`.                         |
| 400         | `invalid_list_control_mode`            | The provided `list_control_mode` is not `all`, `include`, or `exclude`.                            |
| 400         | `invalid_list_control_ids`             | `list_control_ids` is not a list of integers.                                                      |
| 400         | `missing_link_placeholder`             | The message must contain at least one `{{linkN}}` placeholder.                                     |
| 400         | `missing_offer_links_for_placeholders` | One or more `{{linkN}}` placeholders in the message do not have a matching entry in `offer_links`. |
| 400         | `missing_offer_link_key`               | An entry in `offer_links` is missing the required `key` field.                                     |
| 400         | `missing_offer_link_offer_id`          | An entry in `offer_links` is missing the required `offer_id` field.                                |
| 400         | `invalid_offer_link_offer_id`          | An `offer_id` in `offer_links` is not a valid 24-character hexadecimal ObjectId.                   |
| 401         | `invalid_credentials`                  | API key is missing or invalid.                                                                     |
| 403         | `account_suspended`                    | Your account is suspended. Resolve outstanding billing or contact support.                         |
| 429         | `rate_limited`                         | Request throttled; retry with exponential backoff after the window resets.                         |
| 400         | `offer_not_found`                      | An offer referenced in `offer_links` does not exist or does not belong to your account.            |

## Next Steps

<CardGroup cols={2}>
  <Card title="Creative Templates" icon="paintbrush" href="/guides/creatives/templates">
    Learn template best practices
  </Card>

  <Card title="Create Schedule" icon="calendar" href="/api-reference/v2/schedules/create-schedule">
    Use your creative in a campaign
  </Card>
</CardGroup>
