{
"success_count": 3,
"error_count": 0,
"total_revenue": 46.24,
"errors": []
}
{
"success_count": 2,
"error_count": 1,
"total_revenue": 37.49,
"errors": [
{
"index": 2,
"message_id": "i9j0k1l2",
"code": "message_not_found",
"error": "Message ID not found"
}
]
}
{
"error": "records array is required",
"code": "missing_records"
}
{
"error": "Maximum 1000 records per request",
"code": "too_many_records"
}
Data Import (v2)
Import Revenue History
Import historical revenue records for previously sent messages.
POST
/
v2
/
history
/
revenue
{
"success_count": 3,
"error_count": 0,
"total_revenue": 46.24,
"errors": []
}
{
"success_count": 2,
"error_count": 1,
"total_revenue": 37.49,
"errors": [
{
"index": 2,
"message_id": "i9j0k1l2",
"code": "message_not_found",
"error": "Message ID not found"
}
]
}
{
"error": "records array is required",
"code": "missing_records"
}
{
"error": "Maximum 1000 records per request",
"code": "too_many_records"
}
Bulk import up to 1,000 historical revenue records per request. Each record is tied to an existing message and offer. Successfully imported records automatically update the contact’s per-list stats:
Authenticated requests can also fail with Per-record errors (
revenue_total, conversion_count, and last_revenue_at.
Authentication
string
required
Your Trackly SMS API key. Format:
trk_[32-char-alphanumeric].Body Parameters
array
required
An array of revenue records to import. Maximum of 1,000 records per request. Each record accepts the following fields:
Show Record fields
Show Record fields
string
required
The message ID this revenue is associated with. The message must already exist in the system.
string
required
The offer ID this revenue is associated with. The offer must already exist in the system.
float
required
The revenue amount to attribute.
float
default:"0"
The payout amount associated with this revenue event.
string
default:"migration"
How the revenue was attributed. Defaults to
migration for historical imports. Common values: sale, click, send, migration. This field accepts any string value for the history import endpoint.datetime
The revenue event timestamp in ISO 8601 format. Defaults to the current time if omitted.
Response Fields
integer
Number of revenue records successfully imported.
integer
Number of records that failed validation or processing.
float
Sum of all successfully imported revenue amounts.
array
Array of error objects (maximum 100 returned). Each object contains:
index(integer) — Position of the failed record in the input array.message_id(string) — Themessage_idof the failed record.code(string) — Machine-readable error code.error(string) — Human-readable error description.
cURL
curl -X POST https://api.tracklysms.com/api/v2/history/revenue \
-H "X-Api-Key: trk_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"records": [
{
"message_id": "a1b2c3d4",
"offer_id": "offer_123",
"revenue": 24.99,
"payout": 5.00,
"attribution_type": "sale",
"timestamp": "2025-11-15T16:00:00Z"
},
{
"message_id": "e5f6g7h8",
"offer_id": "offer_456",
"revenue": 12.50,
"timestamp": "2025-11-15T17:30:00Z"
},
{
"message_id": "i9j0k1l2",
"offer_id": "offer_123",
"revenue": 8.75,
"attribution_type": "migration"
}
]
}'
message_id is an opaque identifier — do not assume a fixed length or format. Store them as variable-length strings.Python
import requests
response = requests.post(
"https://api.tracklysms.com/api/v2/history/revenue",
headers={
"X-Api-Key": "trk_your_api_key_here",
"Content-Type": "application/json",
},
json={
"records": [
{
"message_id": "a1b2c3d4",
"offer_id": "offer_123",
"revenue": 24.99,
"payout": 5.00,
"attribution_type": "sale",
"timestamp": "2025-11-15T16:00:00Z",
},
{
"message_id": "e5f6g7h8",
"offer_id": "offer_456",
"revenue": 12.50,
"timestamp": "2025-11-15T17:30:00Z",
},
{
"message_id": "i9j0k1l2",
"offer_id": "offer_123",
"revenue": 8.75,
"attribution_type": "migration",
},
],
},
)
print(response.json())
Node.js
const response = await fetch("https://api.tracklysms.com/api/v2/history/revenue", {
method: "POST",
headers: {
"X-Api-Key": "trk_your_api_key_here",
"Content-Type": "application/json",
},
body: JSON.stringify({
records: [
{
message_id: "a1b2c3d4",
offer_id: "offer_123",
revenue: 24.99,
payout: 5.0,
attribution_type: "sale",
timestamp: "2025-11-15T16:00:00Z",
},
{
message_id: "e5f6g7h8",
offer_id: "offer_456",
revenue: 12.5,
timestamp: "2025-11-15T17:30:00Z",
},
{
message_id: "i9j0k1l2",
offer_id: "offer_123",
revenue: 8.75,
attribution_type: "migration",
},
],
}),
});
const data = await response.json();
console.log(data);
{
"success_count": 3,
"error_count": 0,
"total_revenue": 46.24,
"errors": []
}
{
"success_count": 2,
"error_count": 1,
"total_revenue": 37.49,
"errors": [
{
"index": 2,
"message_id": "i9j0k1l2",
"code": "message_not_found",
"error": "Message ID not found"
}
]
}
{
"error": "records array is required",
"code": "missing_records"
}
{
"error": "Maximum 1000 records per request",
"code": "too_many_records"
}
Error Codes
Only two conditions reject the whole request. Every other error is reported per record: the request still returns201, and each failed record appears in the response’s errors[] array with a code (see the Partial Success example above).
Request errors (HTTP status)
| HTTP Status | Error Code | Description |
|---|---|---|
| 400 | missing_records | The records field is required and must be a non-empty array. |
| 413 | too_many_records | Exceeded the maximum of 1,000 records per request. |
401 invalid_credentials or 403 account_suspended — see Error Codes.
Per-record errors (errors[].code, returned with HTTP 201)
| Error Code | Description |
|---|---|
missing_message_id | A record is missing the message_id field. |
missing_offer_id | A record is missing the offer_id field. |
missing_revenue | A record is missing the revenue field. |
message_not_found | No message exists with the given message_id. |
offer_not_found | No offer exists with the given offer_id. |
contact_not_found | The contact associated with the message could not be found. |
save_error | An unexpected error occurred while saving the record. |
Next Steps
Reporting Overview
Analyze revenue data
Bulk Create Contacts
Import contacts alongside history