Transactions API

The Transactions API returns the complete record of every message sent through your account: status, price, operator, and delivery time, across all eight channels. One GET endpoint, one predictable JSON envelope.

QuestionThe API answers with
Did it arrive?status and statusdescription, from Sent to Delivered
How long did it take?deliverytime in seconds, plus readbyrecipient where reads are reported
What did it cost?price per message and running totals in message and invoice currency
Which operator carried it?operatorname and the mccmnc operator code
Which of my records is this?your own reference, so the data lines up without a mapping table

📘

Querying efficiently

Response time tracks how much data your query touches. For fast, reliable responses: keep date ranges small, request only the fields you need with omit, and fetch pages one after another. See Performance and recommended usage.

Authentication

Authenticate your calls with your product token or with the CM SSO cookie.

MethodHow
Product tokenSend the header X-CM-PRODUCTTOKEN with your product token as its value. Standard for server-to-server calls.
CM SSOSend your CM.com platform session cookie with the request.
HostStatusBase URL
api.cm.comRecommendedhttps://api.cm.com/v1.2/transactions/
api.cmtelecom.comLegacy alias, still workshttps://api.cmtelecom.com/v1.2/transactions/

Point new integrations at api.cm.com. Anything already running on api.cmtelecom.com keeps working, so there is no rush to migrate.

Quick start

Every call is a GET request. Give the API a date range and read the result out of the envelope.

curl "https://api.cm.com/v1.2/transactions/?startdate=2026-10-22T08:30&enddate=2026-10-22T09:00&channel=WhatsApp" \
  -H "X-CM-PRODUCTTOKEN: your-product-token"
{
    "status": 1,
    "message": "Ok",
    "summary": {
        "direction": "out",
        "totalTransactions": 1,
        "totalPrice": 0.04,
        "priceCurrency": "EUR"
    },
    "result": [
        {
            "recipient": "0031600000000",
            "channel": "WhatsApp",
            "status": 20,
            "statusdescription": "Delivered",
            "operatorname": "NL - Vodafone",
            "deliverytime": 7
        }
    ]
}

Delivery status

Every outgoing message moves through the same path. Three states are in flight, three are final. The status field carries the numeric code. Incoming messages carry no status.

CodeStatusState
19SentIn transit
37AcceptedIn transit
20DeliveredDelivered
21FailedFailure (final)
40RejectedFailure (final)
22CancelledCancelled (final)

Performance and recommended usage

A few habits keep your queries fast and reliable.

HabitWhy it helps
Keep date ranges tightOne month is the ceiling, but narrower is faster. For large exports, split the work day by day.
Ask only for what you useomit=totalTransactions,totalprice,totaltariff skips the count and sum step entirely.
Page one at a timeRequest the next page only after the previous one lands. Parallel pages compete and invite timeouts.
Avoid deep offsetsLarge startat values get slower the deeper they go. Prefer narrower windows.

🚧

Timeouts under heavy load

A request can occasionally return HTTP 504 during peak usage. Build a retry with backoff into your integration, and the habits above keep it rare.

Response

The result set is wrapped in an envelope that carries information about the set. Whatever you filter for, the shape stays the same.

Envelope

PropertyValue TypeDescription
statusInteger1 for successful request processing
messageStringOk, when nothing exceptional happened

📘

An empty result array means there are no transactions for the given parameters.

Summary

Holds all applied filtering information, plus some aggregate information.

PropertyValue TypeDescription
startDateStringThe start date formatted in ISO8601
endDateStringThe end date formatted in ISO8601
directionStringWhether the message was in incoming or out outgoing
totalTransactionsIntegerAmount of transactions in the result array
totalPriceFloatTotal price of all messages in the result array
priceCurrencyStringPrice currency as ISO 4217 currency code
localPriceFloatPrice you will pay for the messages in your currency
localCurrencyStringCurrency used for your invoice as ISO 4217 currency code
totalTariffIntegerThe sum of the Tariff field. This tariff applies to premium SMS messages, where the recipient is charged for receiving the SMS

Pagination

PropertyValue TypeDescription
currentPageIntegerCurrent page number
totalPagesIntegerTotal available pages
pageSizeIntegerItems per page

Result

The array that holds the result set, one object per message.

PropertyValue TypeDescription
senderStringSender's phone number
recipientStringRecipient's phone number
messageStringMessage content
standarderrorNull/StringStandard error code
errordescriptionStringError description
statusIntegerMessage status code (null for incoming messages)
statusdescriptionStringStatus description
createdString (ISO 8601)Message creation timestamp
countryisoStringCountry in ISO3166 notation
countrynameStringCountry name
mccmncStringMobile country code and Mobile network code
operatornameStringMobile operator name
deliverytimeIntegerDelivery time in seconds
datacodingschemeIntegerData coding scheme
userdataheaderStringUser data header
channelStringCommunication channel
priceInteger/FloatMessage price
currencyStringCurrency of price
localPriceInteger/FloatLocal currency price
localCurrencyStringLocal currency code
tariffInteger/FloatTariff rate
premiumBooleanIndicates premium service
customgroupingNull/StringCustom grouping field
customgrouping2Null/StringCustom grouping field 2
customgrouping3Null/StringCustom grouping field 3
referenceStringUnique message reference
convertedNull/StringConverted content (if any)
directionStringMessage direction (in/out)
multipartNull/BooleanIndicates multipart message
readbyrecipientString (ISO 8601)Read timestamp

Full examples

Outgoing (out) is the default direction: messages sent to a mobile phone. Incoming (?direction=in) covers messages sent from a mobile phone.

{
    "status": 1,
    "message": "Ok",
    "pagination": {
        "currentPage": 1,
        "totalPages": 1,
        "pageSize": 1000
    },
    "summary": {
        "startDate": "2026-10-22T08:30:00+02:00",
        "endDate": "2026-10-22T09:00:00+02:00",
        "direction": "out",
        "totalTransactions": 1,
        "totalPrice": 0,
        "priceCurrency": "EUR",
        "localPrice": 0,
        "localCurrency": "USD",
        "totalTariff": 0
    },
    "result": [
        {
            "sender": "009190000000",
            "recipient": "009190000000",
            "message": "",
            "standarderror": null,
            "errordescription": "",
            "status": 20,
            "statusdescription": "Delivered",
            "created": "2026-10-22T08:51:55+02:00",
            "countryiso": "IN",
            "countryname": "India",
            "mccmnc": "404997",
            "operatorname": "IN - Unspecified operator",
            "deliverytime": 7,
            "datacodingscheme": 0,
            "userdataheader": "",
            "channel": "WhatsApp",
            "price": 0,
            "currency": "EUR",
            "localPrice": 0,
            "localCurrency": "USD",
            "tariff": 0,
            "premium": false,
            "customgrouping": null,
            "customgrouping2": null,
            "customgrouping3": null,
            "reference": "47ce194c-7f83-4c05-ad1a-46697dd86a3e",
            "converted": null,
            "direction": "out",
            "multipart": null,
            "readbyrecipient": "2026-10-22T09:22:31+02:00"
        }
    ]
}
{
    "status": 1,
    "message": "Ok",
    "pagination": {
        "currentPage": 1,
        "pageSize": 1000,
        "totalPages": 1
    },
    "summary": {
        "direction": "in",
        "startDate": "2026-02-01T00:00:00+01:00",
        "endDate": "2026-02-02T00:00:00+01:00",
        "totalTransactions": 1
    },
    "result": [
        {
            "channel": "SMS",
            "countryiso": "NL",
            "countryname": "Netherlands",
            "created": "2026-02-01T23:58:20+01:00",
            "customgrouping": null,
            "customgrouping2": null,
            "customgrouping3": null,
            "datacodingscheme": 0,
            "direction": "in",
            "mccmnc": "20404",
            "message": "I love CM.com's transaction API",
            "operatorname": "NL - Vodafone",
            "premium": false,
            "price": 0,
            "recipient": "3669",
            "reference": "510661747",
            "sender": "0031601234567",
            "status": null,
            "tariff": 0,
            "userdataheader": ""
        }
    ]
}

Required filters

Date range

  • startdate={ISO8601}
  • enddate={ISO8601}

These are the only required parameters. When the time is left off it is filled with zeroes, so 2026-05-05 is read as 2026-05-05T00:00:00. A maximum range of 1 month is allowed.

Optional filters

Channel

Filter transactions per channel.

ChannelDescription
SMSShort Message Service
PUSHPush Notification
VoiceVoice Call
RCSRich Communication Services
ViberViber Messaging
WhatsAppWhatsApp Messaging
iMessageApple iMessage
LineLine Messaging

Usage: channel=WhatsApp

Direction

PropertyValue TypeDescription
directionStringDefines the message direction (in or out)
  • out (default): country code of the recipient
  • in: country code of the sender

Recipient

Filter by the receiver of a transaction.

PropertyValue TypeDescription
recipientStringComma-separated list of recipients (phone numbers or shortcodes)
referenceStringComma-separated list of customer-provided references
  • By recipient: recipient=0031601234567,0031607654321
  • By reference: reference=customer-known-identifier1,customer-known-identifier2

Sender

Filter by the sender name of a transaction.

PropertyValue TypeDescription
senderStringComma-separated list of senders (company name, shortcode, or longcode)

Usage: sender=3669,0031601234567

Message

Filter for specific message content. Works in both directions and supports the * wildcard.

  • message=This very specific message
  • message=This*message

CountryISO

Filter by recipients in specific countries.

PropertyValue TypeDescription
countryisoStringComma-separated list of country ISO codes

Example: countryiso=NL,DE,FR

MCC MNC

Filter by operator. In 20404, 204 identifies the country (the Netherlands) and 04 identifies the operator (Vodafone).

PropertyValue TypeDescription
mccmncStringComma-separated list of operator identification codes

Example: mccmnc=20404,20405

Statuscode

Filter by the status code returned by this API.

PropertyValue TypeDescription
statuscodeIntegerComma-separated list of status codes

Example: statuscode=20,21,40 (Delivered, Failed, Rejected)

Errorcode

Filter by the error codes this API returns.

PropertyValue TypeDescription
errorcodeIntegerComma-separated list of error codes

Analyticserror

Filter by the readable error code the analytics API uses.

CodeDescription
0Unknown recipient
1Unknown failure
2Too many messages to recipient
3Recipient temporarily unavailable
4Recipient blacklisted
5Message rejected by operator
6Message malformed
7Handset issue
8Recipient has no credit
9Age verification failed
10Delivery time expired

Converted

Filter by converted messages: converted=true.

Multipart

Handles messages split into several parts (for example an SMS over 160 characters).

  • Show only the first part: multipart=firstpartonly
  • Show all parts of one message: multipart={multipart.identifier} (best combined with the recipient filter)

Customgrouping

Filter on the custom groupings you set when sending.

PropertyValue TypeDescription
customgroupingStringComma-separated string of custom groupings
customgrouping2StringComma-separated string of custom groupings 2
customgrouping3StringComma-separated string of custom groupings 3

Example: customgrouping=reference1,reference2,reference3

SMSCampaign

Return every transaction that belongs to a certain SMS campaign.

PropertyValue TypeDescription
smscampaignStringFilter by SMS campaign identifier (GUID)

Your campaign identifier is a GUID, found in the URL of the campaign edit view or in the CustomGrouping property of messages.

Omit

Skip properties you do not need. Omitting the aggregates also skips the count and sum step, which makes the response faster.

ValueSkips
totalTransactionsThe transaction count for the result set
totalpriceThe price calculation for the result set
totaltariffThe tariff calculation for the result set
resultThe paginated list of messages

Example: omit=totalTransactions,totalprice,totaltariff

Pagination

Pagesize

PropertyValue TypeDescription
pagesizeIntegerNumber of items per page (default 1000, max 7500)

Example: pagesize=10

Startat

PropertyValue TypeDescription
startatIntegerThe starting page for pagination (default 1)

Example: startat=7

Negate

Invert a filter. To pull every message to recipients outside the Netherlands, supply the filter and then negate its key:

?startdate=...&enddate=...&countryiso=nl&negate=countryiso

Extra resources

Alongside /transactions/, five lookups hand you the exact values the filters accept.

ResourceReturns
/transactions/countriesEvery country with its ISO code
/transactions/errorcodesAll error codes and their descriptions
/transactions/mediumsAll channels with their numeric medium id
/transactions/operatorsOperators with their MCC MNC identifiers
/transactions/statuscodesThe six status codes and their labels

The /transactions/statuscodes resource returns:

[
    { "id": 19, "description": "Sent" },
    { "id": 20, "description": "Delivered" },
    { "id": 21, "description": "Failed" },
    { "id": 22, "description": "Cancelled" },
    { "id": 37, "description": "Accepted" },
    { "id": 40, "description": "Rejected" }
]

Did this page help you?