Skip to content

API Send SMS

This is the high-throughput version of Quick Send SMS, built for applications that send continuously or in large bursts. It sends the same messages, from the same sender IDs, with the same request body — it just accepts your request and confirms it immediately rather than holding the connection open while every recipient is processed.

Reach for it when Quick Send SMS is your bottleneck: high sustained volume, traffic spikes, or a send loop where response time matters more than getting per-recipient detail in the reply.

Because the work happens after the reply, three things change for your integration: the success status, the response body, and when certain failures become visible. Those are the whole of the migration — see Switching from Quick Send SMS.

How it compares to Quick Send SMS

Quick Send SMSAPI Send SMS
EndpointPOST /api/v1/gatewayPOST /api/v3/apiClient/sendMessage
Messages, senders, pricingIdentical
Request bodySame shape, minus the fields listed under Parameters
Success status200202 Accepted
Response bodydata.queueResponse with a per-recipient resultreferenceId, acceptedCount, invalidContacts
Per-recipient MessageId in the responseYesNo — see Correlating a send with its messages
Response envelopeStandard Cellcast envelope (status, data, error, …)Plain JSON, no envelope
Low credit, unregistered sender, opted-out recipientCan fail the requestReported after the response — see Failures you will not see in the response
Scheduled and delayed sendingSupportedNot supported
Best forLow volume, or when you need per-recipient detail in the replySustained volume and bursts

Switching from Quick Send SMS

  1. Change the URL to https://api.cellcast.com/api/v3/apiClient/sendMessage.
  2. Treat 202 as success, not just 200.
  3. Read the response as plain JSON — this endpoint does not wrap its success response in the standard Cellcast envelope, so there is no status or data field on a 202. Errors are not uniform either: validation and queueing errors use the Cellcast envelope, while authentication errors come back as { code, message, stack }. See Responses for both shapes.
  4. Stop reading queueResponse. Get per-message outcomes from your delivery webhook (forwardWebhookUrl), or from Get List Sent Messages.

Parameters

Headers Parameters

ParametersDescription
AuthorizationPlease add provided Bearer token - linked to your Cellcast account. Check here
Idempotency-KeyOptional. A unique string of your own for this send, so a retry after a network timeout is suppressed instead of sending again. Best-effort and time-limited — see Retrying safely.

Request Body Parameters

The same shape as Quick Send SMS — the body is passed through to the same sending pipeline — with the exceptions called out below the table.

NameExampleDescription
sender#SharedNum# or Sender ID (Custom ID)Sender ID (Custom ID): Valid characters: A-Z a-z 0-9, space, and Dash (-). A numeric sender ID can be a maximum length of 16 digits. An alpha-numeric Sender ID can be a maximum length of 11 characters. If 'sender' is left blank, the system will default to '#SharedNum#'. *Note: some accounts are billed at 1.3 credits per SMS when sending from a business name or custom number. This is an account-level setting rather than a fixed surcharge — check your own rate card, or ask Cellcast support, before assuming either price.
messageSMS Text goes hereString - Required field. To add a new line to the message, use "\r\n" in the message string with only double quotes.
contacts["+61400000000"]Required field. A JSON-encoded array of number strings, such as ["+61400000000", "+61400000001"], or a single comma-separated string. Unlike Bulk Send SMS, object entries such as {"number": …, "customString": …} are not supported here. You can include up to 500 valid numbers in a single API call. Supported number formats include : "+61400000000", "61400000000", "0400000000", "400000000"
senderTypebusinessNameOptional, case-sensitive. One of businessName, customNumber, dedicatedNumber, #SharedNum#. For any non-shared sender the value is re-derived from your account's registered sender IDs during processing, so an incorrect value here is corrected rather than honoured.
templateId6682440ea000000000000000Optional. Send a saved template. The template replaces message when it resolves, but message is still required and must be non-blank — this endpoint validates it before the template is looked up, so templateId alone returns 400. See Get SMS Template.
longUrl[{"_id": "68ef60842000000000000000", "shortUrl": "cell", "longUrl": "www.cellcast.com"}]Attach tracking links to embed short URLs in your message. Reference them as gosite.au/{shortUrl} inside message. To create a link, see Create Tracking Link. To list and get _id/shortUrl/longUrl, see Get Tracking Links.
optouttrueSet to true to enable the Custom Opt-Out feature using the optoutId.
optoutId6682440ea000000000000000The unique identifier of the Custom Opt-Out to be used. Check here to get your Custom Opt-Out ID. Leave this empty to use the default custom opt-out set here
replyStopToOptOutfalseSet to true to allow users to opt out by replying "STOP".
customStringAllow any text in Custom String. eg. ZOHO, ZappierAllowed characters: letters, numbers, and dashes in Custom String. For the message report, see Get Custom String Message Report
campaign_typepromotionalOptional. Campaign classification, as on Quick Send SMS.
forwardReplyTo[email protected]Optional. Email address to forward replies to.
forwardWebhookUrlhttps://example.com/hooks/dlrOptional but recommended. Your endpoint for delivery receipts and replies, pushed as they happen. You can also query message reports afterwards — see Correlating a send with its messages.

Not supported on this endpoint

scheduleAt and delay are ignored. A request carrying either is sent immediately — you will not get an error, and the message will not wait. For scheduled or delayed sending use Quick Send SMS or Bulk Send SMS.

countryCode is also ignored; recipient numbers are validated as Australian numbers.

Custom fields work exactly as they do for Quick Send SMS — see Using Custom Fields in the Message Body.

Failures you do get in the response

These are checked while your request is still open, and come back as a 400 with nothing queued — exactly as they would on Quick Send SMS:

CheckError message
message present and not blankMessage is required
message is at most 10 SMS partsLimit exceeded: Only 10 message parts are allowed.
contacts present and not emptyContacts are required
At least one number is validNo valid contacts
At most 500 valid numbersMax number of contacts allowed in QuickSMS: 500

Two notes on contacts:

  • Duplicates are collapsed. The same number listed five times is accepted once and billed once. acceptedCount reflects the deduplicated total.
  • Invalid numbers do not fail the request. As long as one number is valid, you get a 202; the rejected ones come back in invalidContacts with a reason. The 500 limit applies to the valid numbers that remain after invalid ones and duplicates are removed.

Correlating a send with its messages

referenceId identifies your request, not the messages it produces — it is not stamped onto the individual messages and cannot be looked up. There is no endpoint that takes a referenceId.

To tie messages back to a request, use customString: set your own value per send and read it back through Get Custom String Message Report. Set forwardWebhookUrl as well, so delivery receipts reach you as they happen.

Failures you will not see in the response

These are checked after your request has already been answered, so a 202 does not mean they passed. The request is accepted and the affected messages are then not sent:

ConditionWhat happens
Insufficient creditMessages are not sent. Quick Send SMS fails the call with 422 instead — use it if you need that.
Sender ID not registered to your accountThe whole request is dropped, every recipient, not just some. Quick Send SMS rejects this with a 400.
Recipient on your opt-out list, or a blocked numberThe message is never sent — opt-out is always enforced — but the credit is still charged and not refunded. This matches how bulk campaigns bill; Quick Send SMS does not charge for these.
Content caught by fraud / offensive-word filteringThe campaign is held for manual approval instead of being sent.
templateId cannot be resolvedThe whole request is dropped. The template is looked up after the response, so a bad id is not reported to you.

WARNING

Because none of the above reaches you in the response, confirm a new integration end-to-end on a small send before switching production traffic over — in particular that your sender is registered and approved for your account.

Retrying safely

Without an Idempotency-Key, a retry is treated as a brand new send and the messages go out again — the same behaviour as Quick Send SMS.

Send an Idempotency-Key header with a unique value per send (an order ID, a UUID). The same key always produces the same referenceId, and processing is designed to suppress a duplicate carrying a referenceId it has already completed — so you can retry a request that timed out without knowing whether the original arrived. Keys are scoped to your account, so your key can never collide with another customer's.

Note that the retry is accepted and queued again; the suppression happens during processing, not at the time of your call. You will get a 202 either way.

WARNING

Duplicate suppression lasts roughly one hour after the original send finishes processing. A retry with the same key after that window is treated as a new send. It is best-effort, not a delivery guarantee — do not rely on it as your only safeguard against duplicate sends.

Code Samples

Post https://api.cellcast.com/api/v3/apiClient/sendMessage

bash
curl --location 'https://api.cellcast.com/api/v3/apiClient/sendMessage' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer {{API_KEY}}' \
--header 'Idempotency-Key: order-4417-attempt-1' \
--data '{
  "message": "Hi {{[First Name]}}, Test Message Visit gosite.au/cell ",
  "contacts": [
    "+61400000000",
    "+61400000001"
  ],
  "sender": "+61400000001",
  "longUrl": [
    {
        "_id": "68ef60842000000000000000",
        "longUrl": "www.cellcast.com",
        "shortUrl": "cell"
    }
  ]
}'
js
const axios = require("axios");

const sendSMS = async () => {
  try {
    const response = await axios.post(
      "https://api.cellcast.com/api/v3/apiClient/sendMessage",
      {
        message: "Hi {{[First Name]}}, Test Message Visit gosite.au/cell",
        contacts: ["+61400000000", "+61400000001"],
        sender: "+61400000001",
        longUrl: [
          {
            _id: "68ef60842000000000000000",
            longUrl: "www.cellcast.com",
            shortUrl: "cell"
          }
        ]
      },
      {
        headers: {
          "Content-Type": "application/json",
          Accept: "application/json",
          Authorization: "Bearer {{API_KEY}}",
          "Idempotency-Key": "order-4417-attempt-1",
        },
      }
    );
    // 202 Accepted — plain JSON, no envelope.
    console.log(response.data.referenceId, response.data.acceptedCount);
  } catch (error) {
    console.error(error.response.data);
  }
};

Replace with the actual API key that you own.

Responses

Response Body

NameExampleDescription
referenceId6544b052-55da-48c5-a0b7-23be013b4006Identifier for this request. Used for duplicate suppression on retries (see Retrying safely) and useful in your own logs when contacting support. See the note below on correlating it with individual messages.
acceptedCount2How many recipients were accepted for sending, after invalid numbers and duplicates were removed.
invalidContacts[]Numbers that were rejected, each with the reason. Empty when every number was valid.
invalidContacts[].Contact123The number exactly as you supplied it.
invalidContacts[].ErrorNumber is less than 9 digitHuman-readable reason.
invalidContacts[].ErrorTypeless_nine_digitMachine-readable reason code.

202 Accepted

Two numbers accepted, one rejected. Note there is no envelope around this body.

json
{
    "referenceId": "6544b052-55da-48c5-a0b7-23be013b4006",
    "acceptedCount": 2,
    "invalidContacts": [
        {
            "Contact": "123",
            "Error": "Number is less than 9 digit",
            "ErrorType": "less_nine_digit"
        }
    ]
}

202 Accepted (with Idempotency-Key)

When you send an Idempotency-Key, the referenceId is derived from it, so retrying with the same key returns the same referenceId.

json
{
    "referenceId": "a00f454bc35244826b30f8910feb7611a45c90527fa42dbbb9d097322a97c7cb",
    "acceptedCount": 1,
    "invalidContacts": []
}

400 Bad Request (message missing)

json
{
    "app_type": "web",
    "app_version": "1.0",
    "maintainence": 0,
    "new_version": 0,
    "force_update": 0,
    "invalid_token": 0,
    "refresh_token": "",
    "show_message": 0,
    "is_enc": false,
    "status": false,
    "message_type": "toast",
    "message": "Message is required",
    "data": {},
    "error": {
        "message": "Message is required"
    }
}

400 Bad Request (no valid contacts)

Every supplied number was invalid. When at least one is valid you receive a 202 instead, with the rest listed in invalidContacts.

json
{
    "app_type": "web",
    "app_version": "1.0",
    "maintainence": 0,
    "new_version": 0,
    "force_update": 0,
    "invalid_token": 0,
    "refresh_token": "",
    "show_message": 0,
    "is_enc": false,
    "status": false,
    "message_type": "toast",
    "message": "No valid contacts",
    "data": {},
    "error": {
        "contacts": "No valid contacts"
    }
}

400 Bad Request (too many contacts)

json
{
    "app_type": "web",
    "app_version": "1.0",
    "maintainence": 0,
    "new_version": 0,
    "force_update": 0,
    "invalid_token": 0,
    "refresh_token": "",
    "show_message": 0,
    "is_enc": false,
    "status": false,
    "message_type": "toast",
    "message": "Max number of contacts allowed in QuickSMS: 500",
    "data": {},
    "error": {
        "contacts": "Max number of contacts allowed in QuickSMS: 500"
    }
}

401 Unauthorized

json
{
  "code": 401,
  "message": "Token expired",
  "stack": "APIError: Token expired ...."
}

500 Internal Server Error

The send could not be queued. Nothing was accepted, so it is safe to retry — reuse the same Idempotency-Key if you sent one.

json
{
    "app_type": "web",
    "app_version": "1.0",
    "maintainence": 0,
    "new_version": 0,
    "force_update": 0,
    "invalid_token": 0,
    "refresh_token": "",
    "show_message": 0,
    "is_enc": false,
    "status": false,
    "message_type": "toast",
    "message": "SEND_INGEST_SQS_URL is not configured",
    "data": {},
    "error": {
        "serverError": "SEND_INGEST_SQS_URL is not configured"
    }
}