curl -X POST https://api.tracklysms.com/api/v2/links/shorten \
-H "X-Api-Key: trk_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/landing-page",
"listId": 42
}'
import requests
response = requests.post(
"https://api.tracklysms.com/api/v2/links/shorten",
headers={
"X-Api-Key": "trk_your_api_key_here",
"Content-Type": "application/json",
},
json={
"url": "https://example.com/landing-page",
"listId": 42,
},
)
data = response.json()
print(data["shortUrl"]) # e.g. https://yourdomain.com/Ab3kX9q
const response = await fetch("https://api.tracklysms.com/api/v2/links/shorten", {
method: "POST",
headers: {
"X-Api-Key": "trk_your_api_key_here",
"Content-Type": "application/json",
},
body: JSON.stringify({
url: "https://example.com/landing-page",
listId: 42,
}),
});
const data = await response.json();
console.log(data.shortUrl);
{
"shortUrl": "https://yourdomain.com/Ab3kX9q",
"linkId": "Ab3kX9q",
"destinationUrl": "https://example.com/offer?aff_sub=12345",
"domain": "https://yourdomain.com",
"offerId": "6651a3ef1234567890abcdef",
"filterBots": false
}
{
"error": "url or offerId is required",
"code": "missing_url_or_offer"
}
{
"error": "URL must use http or https scheme",
"code": "invalid_url_scheme"
}
{
"error": "metadata cannot exceed 10 keys",
"code": "invalid_metadata"
}
{
"error": "Blocked URL: URL must use HTTPS",
"code": "unsafe_url"
}
{
"error": "Offer not found",
"code": "offer_not_found"
}
{
"error": "No link domain configured for this list",
"code": "no_domain_configured"
}
Links (v2)
Shorten Link
Create a trackable short link for any URL or offer.
POST
/
v2
/
links
/
shorten
curl -X POST https://api.tracklysms.com/api/v2/links/shorten \
-H "X-Api-Key: trk_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/landing-page",
"listId": 42
}'
import requests
response = requests.post(
"https://api.tracklysms.com/api/v2/links/shorten",
headers={
"X-Api-Key": "trk_your_api_key_here",
"Content-Type": "application/json",
},
json={
"url": "https://example.com/landing-page",
"listId": 42,
},
)
data = response.json()
print(data["shortUrl"]) # e.g. https://yourdomain.com/Ab3kX9q
const response = await fetch("https://api.tracklysms.com/api/v2/links/shorten", {
method: "POST",
headers: {
"X-Api-Key": "trk_your_api_key_here",
"Content-Type": "application/json",
},
body: JSON.stringify({
url: "https://example.com/landing-page",
listId: 42,
}),
});
const data = await response.json();
console.log(data.shortUrl);
{
"shortUrl": "https://yourdomain.com/Ab3kX9q",
"linkId": "Ab3kX9q",
"destinationUrl": "https://example.com/offer?aff_sub=12345",
"domain": "https://yourdomain.com",
"offerId": "6651a3ef1234567890abcdef",
"filterBots": false
}
{
"error": "url or offerId is required",
"code": "missing_url_or_offer"
}
{
"error": "URL must use http or https scheme",
"code": "invalid_url_scheme"
}
{
"error": "metadata cannot exceed 10 keys",
"code": "invalid_metadata"
}
{
"error": "Blocked URL: URL must use HTTPS",
"code": "unsafe_url"
}
{
"error": "Offer not found",
"code": "offer_not_found"
}
{
"error": "No link domain configured for this list",
"code": "no_domain_configured"
}
Create a trackable short link for any URL or an offer from your catalog. Unlike
POST /v2/links (which requires Offer Management and only supports partnership offers), this endpoint works with any URL and with SMS Offers.
Requires SMS product. This endpoint is available to any account with the SMS product enabled. Returns
403 product_not_enabled otherwise.How It Works
There are two modes:- URL mode — provide a raw
urland get a short link pointing directly at it. No affiliate tracking. - Offer mode — provide an
offerId(from your SMS Offers, not partnership offers) and the endpoint resolves the offer’s tracking URL with proper TUNE/Everflow parameters, preserving affiliate attribution.
Short link (list domain) -> Link tracking service -> Destination URL
Body Parameters
string
Raw destination URL to shorten. Only
https URLs are accepted; http URLs are rejected with 400 unsafe_url. Required unless offerId is provided.string
ID of an SMS offer in your catalog (see List Offers). Required unless
url is provided — url and offerId are mutually exclusive; sending both returns 400 mutually_exclusive.integer
Sending list ID — determines which shortener domain to use. Required unless
phoneNumber is provided.string
Sending list phone number in E.164 format (e.g.
+18005551234). Alternative to listId. Required unless listId is provided.string
Contact phone number in E.164 format. Passed as a macro to offer URL templates (
{{phone}}, also available as {{phone_number}}). Optional.object
Key-value pairs stored on the short link for attribution. For example,
{"source": "ai_agent", "conversation_id": "abc123"}. Optional. Constraints: at most 10 keys; keys must be strings and cannot start with $; values are coerced to strings and cannot exceed 500 characters. Violations return 400 invalid_metadata.Response Fields
string
Full short URL to include in your SMS message body. Uses the list’s configured link shortener domain.
string
Unique short link ID. Appended to the domain to form the
shortUrl.string
The final destination URL that the recipient lands on after redirect.
string
The link shortener domain used for this short link.
string
The SMS offer ID the link is associated with, if an offer was used.
boolean
Whether bot filtering is enabled for this link. Inherited from the offer’s
filter_bots setting when offerId is provided.Examples
Shorten a raw URL
curl -X POST https://api.tracklysms.com/api/v2/links/shorten \
-H "X-Api-Key: trk_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/landing-page",
"listId": 42
}'
import requests
response = requests.post(
"https://api.tracklysms.com/api/v2/links/shorten",
headers={
"X-Api-Key": "trk_your_api_key_here",
"Content-Type": "application/json",
},
json={
"url": "https://example.com/landing-page",
"listId": 42,
},
)
data = response.json()
print(data["shortUrl"]) # e.g. https://yourdomain.com/Ab3kX9q
const response = await fetch("https://api.tracklysms.com/api/v2/links/shorten", {
method: "POST",
headers: {
"X-Api-Key": "trk_your_api_key_here",
"Content-Type": "application/json",
},
body: JSON.stringify({
url: "https://example.com/landing-page",
listId: 42,
}),
});
const data = await response.json();
console.log(data.shortUrl);
Shorten an offer link with metadata
curl -X POST https://api.tracklysms.com/api/v2/links/shorten \
-H "X-Api-Key: trk_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"offerId": "6651a3ef1234567890abcdef",
"phoneNumber": "+18005551234",
"contactPhone": "+15551234567",
"metadata": {
"source": "ai_agent",
"conversation_id": "conv_abc123"
}
}'
response = requests.post(
"https://api.tracklysms.com/api/v2/links/shorten",
headers={
"X-Api-Key": "trk_your_api_key_here",
"Content-Type": "application/json",
},
json={
"offerId": "6651a3ef1234567890abcdef",
"phoneNumber": "+18005551234",
"contactPhone": "+15551234567",
"metadata": {
"source": "ai_agent",
"conversation_id": "conv_abc123",
},
},
)
const response = await fetch("https://api.tracklysms.com/api/v2/links/shorten", {
method: "POST",
headers: {
"X-Api-Key": "trk_your_api_key_here",
"Content-Type": "application/json",
},
body: JSON.stringify({
offerId: "6651a3ef1234567890abcdef",
phoneNumber: "+18005551234",
contactPhone: "+15551234567",
metadata: {
source: "ai_agent",
conversation_id: "conv_abc123",
},
}),
});
const data = await response.json();
console.log(data.shortUrl);
{
"shortUrl": "https://yourdomain.com/Ab3kX9q",
"linkId": "Ab3kX9q",
"destinationUrl": "https://example.com/offer?aff_sub=12345",
"domain": "https://yourdomain.com",
"offerId": "6651a3ef1234567890abcdef",
"filterBots": false
}
{
"error": "url or offerId is required",
"code": "missing_url_or_offer"
}
{
"error": "URL must use http or https scheme",
"code": "invalid_url_scheme"
}
{
"error": "metadata cannot exceed 10 keys",
"code": "invalid_metadata"
}
{
"error": "Blocked URL: URL must use HTTPS",
"code": "unsafe_url"
}
{
"error": "Offer not found",
"code": "offer_not_found"
}
{
"error": "No link domain configured for this list",
"code": "no_domain_configured"
}
Error Codes
| HTTP Status | Error Code | Description |
|---|---|---|
| 400 | missing_url_or_offer | Neither url nor offerId was provided. |
| 400 | mutually_exclusive | Both url and offerId were provided; supply exactly one. |
| 400 | missing_list_identifier | Neither listId nor phoneNumber was provided. |
| 400 | invalid_url_scheme | The url does not use http or https scheme. |
| 400 | invalid_metadata | The metadata object violates a constraint (not an object, >10 keys, non-string key, key starting with $, or value >500 chars). |
| 400 | unsafe_url | The url is blocked by safety checks — for example it uses http instead of https, or it resolves to a private or non-public IP address. |
| 400 | invalid_phone | The phoneNumber is not a valid E.164 phone number. |
| 403 | product_not_enabled | Your account does not have the SMS product enabled. |
| 404 | offer_not_found | No active offer found matching the provided offerId. |
| 404 | list_not_found | The sending list was not found or does not belong to your account. |
| 409 | no_domain_configured | The sending list does not have a link shortener domain configured. |
| 500 | id_collision | Failed to generate a unique link ID after multiple attempts. Retry the request. |
Notes
- The
metadatafield is stored with the short link for attribution tracking. - When
offerIdis provided, the offer’sfilter_botssetting is inherited by the short link. The link tracking service handles bot filtering on click. - Each call creates a new unique short link. There is no deduplication.
- This endpoint is separate from
POST /v2/links, which continues to serve partnership offers only.
Next Steps
Create Link (Offers)
Create links for partnership offers
Link Tracking
Track clicks and attribute conversions