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"
}'
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']}")
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}`);
{
"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": []
}
}
{
"error": "message must contain at least one {{linkN}} placeholder",
"code": "missing_link_placeholder"
}
{
"error": "Offer not found: 665f1a2b3c4d5e6f70819201",
"code": "offer_not_found"
}
{
"error": "Invalid credentials",
"code": "invalid_credentials"
}
Creatives (v2)
Create a Creative
Create a new message creative with offer link placeholders.
POST
/
v2
/
creatives
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"
}'
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']}")
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}`);
{
"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": []
}
}
{
"error": "message must contain at least one {{linkN}} placeholder",
"code": "missing_link_placeholder"
}
{
"error": "Offer not found: 665f1a2b3c4d5e6f70819201",
"code": "offer_not_found"
}
{
"error": "Invalid credentials",
"code": "invalid_credentials"
}
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
string
required
Display name for the creative. Maximum 255 characters.
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.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.Show Offer link properties
Show Offer link properties
string
required
The placeholder key. Must match a placeholder in the message (e.g.
link1 corresponds to {{link1}}).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.
string
Optional URL override. When provided, this URL is used instead of the offer’s default URL.
object
Optional additional query parameters to append to the link URL.
string
default:"active"
Initial status of the creative. Accepted values:
active, paused.string
default:"automated"
The type of creative. Accepted values:
automated, one_time, welcome.string
default:"all"
List targeting control mode. Accepted values:
all, include, exclude.array
List IDs (integers) to include or exclude when
list_control_mode is include or exclude.Response Fields
boolean
Indicates whether the creative was created successfully.
object
The full creative object.
Show Creative object properties
Show Creative object properties
integer
Unique identifier for the creative.
string
Display name of the creative.
string
The message template with
{{linkN}} placeholders.array
Array of offer link objects.
array
Array of offer ID strings referenced by this creative.
string
Current status of the creative.
string
The type of creative.
integer
Estimated character count. Link placeholders are estimated as 23 characters each, plus 34 characters of compliance overhead (e.g. opt-out language).
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.datetime
ISO 8601 timestamp of when the creative was created.
string
Auto-generated unique slug for the creative.
string
List targeting control mode. One of:
all (default), include, exclude.array
List IDs used when
list_control_mode is include or exclude.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.Examples
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"
}'
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']}")
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}`);
{
"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": []
}
}
{
"error": "message must contain at least one {{linkN}} placeholder",
"code": "missing_link_placeholder"
}
{
"error": "Offer not found: 665f1a2b3c4d5e6f70819201",
"code": "offer_not_found"
}
{
"error": "Invalid credentials",
"code": "invalid_credentials"
}
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
Creative Templates
Learn template best practices
Create Schedule
Use your creative in a campaign
⌘I