Send and Receive SMS with the API
Send an SMS or MMS from your own software, receive incoming messages through a webhook, look up what happened to a message you sent, check the capacity you have left, and queue a bulk campaign for a future date. Endpoints, headers, curl examples and the practices that keep your number in good standing.
What you can do
The Private Integrations API lets your own software send and receive messages through your Zonitel numbers: send a single SMS or MMS, receive incoming messages as they arrive, look up what happened to a message you sent, check how much sending capacity you have left, and queue a bulk campaign for a future date. Every request runs against https://api.zonitel.com/api/v3.
If you have not created an access credential yet, start with the Private Integrations guide and come back here.
Before you start
Every request carries your token and your Client identifier from the Credentials tab in Settings > Private Integrations, as headers.
Authorization: Bearer YOUR_TOKEN
X-Client-Id: YOUR_CLIENT_ID
Accept: application/json
Write numbers in full international form, as in +13055550123. The full parameter and response detail for every endpoint is in the interactive API reference, and a Postman collection is linked from the Overview tab of the same screen.
You can only send from a number on your own account that is enabled for messaging. /integrations/numbers lists your numbers, and the Phone Numbers screen shows which of them carry an SMS badge.
Send a text message
curl --request POST \
--url https://api.zonitel.com/api/v3/integrations/sms/send \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'X-Client-Id: YOUR_CLIENT_ID' \
--header 'Content-Type: application/json' \
--data '{"from": "+13055550123", "to": "+17135550199", "text": "Your appointment is confirmed for Tuesday at 10:00."}'
Three fields: from is one of your messaging numbers, to is the recipient, and text is the body. A long message is split into several segments by the carriers and counts as more than one against your balance, so keep transactional messages tight.
The send response contains data.id, data.segments and data.status. Save data.id for the message lookup below. A response of sent does not by itself confirm delivery to the recipient.
Send a picture message
Add a medias array to the same endpoint and the message goes out as an MMS. Each entry is a publicly reachable URL that we fetch at send time, so the file cannot sit behind a login.
curl --request POST \
--url https://api.zonitel.com/api/v3/integrations/sms/send \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'X-Client-Id: YOUR_CLIENT_ID' \
--header 'Content-Type: application/json' \
--data '{"from": "+13055550123", "to": "+17135550199", "text": "Here is the quote.", "medias": ["https://yoursite.com/files/quote.jpg"]}'
text is optional here. Leave it out and the recipient gets the image on its own.
Receive incoming messages
Incoming messages reach your system through a webhook, the same way calls do. You register one URL and we post to it as messages arrive.
From the portal
Go to Settings > Private Integrations and open the Webhooks tab. Paste your address in the SMS field and save. The URL has to be live and answer with HTTP 200 before the save is accepted. Clear the field and save again to stop receiving events.
From the API
curl --request PUT \
--url https://api.zonitel.com/api/v3/integrations/sms/webhooks \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'X-Client-Id: YOUR_CLIENT_ID' \
--header 'Content-Type: application/json' \
--data '{"url": "https://yoursite.com/webhook/sms"}'
The same path answers GET, returning the URL currently registered, and DELETE, which removes it. Your endpoint should acknowledge with HTTP 200 straight away and process afterwards, and it should tolerate the same event arriving twice. You receive two kinds of event — one when a message comes in and one carrying the delivery status of a message you sent — and both payloads are set out field by field in SMS Webhooks.
For the current receiver authentication choices, see SMS Webhooks.
Look up a message you sent
A send returns an identifier for the message. Use it to check what became of that message afterwards.
curl --request GET \
--url https://api.zonitel.com/api/v3/integrations/sms/messages/MESSAGE_UUID \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'X-Client-Id: YOUR_CLIENT_ID' \
--header 'Accept: application/json'
Store that identifier against your own record. It is the only way to tie a row in your system back to a specific message here.
The lookup’s documented status values include created, sent, received, delivered, read and failed. Handle the value actually returned; do not assume every channel provides a read receipt.
Check your remaining capacity
Messages are counted in segments, not in sends, so a long message consumes several. Before a campaign, check what is left rather than discovering the limit halfway through.
curl --request GET \
--url https://api.zonitel.com/api/v3/integrations/sms/stock \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'X-Client-Id: YOUR_CLIENT_ID' \
--header 'Accept: application/json'
GET /integrations/sms/destinations returns the account’s SMS numbers in data, with uuid, number and label. This is an account-number lookup, not a list of international coverage areas. The stock response above returns the remaining total in data.total.
Bulk and scheduled campaigns
A group message goes to a list of recipients in one request, either immediately or at a date you choose. Each recipient carries a name, so the message can be personalised.
curl --request POST \
--url https://api.zonitel.com/api/v3/integrations/sms/groups \
--header 'Authorization: Bearer YOUR_TOKEN' \
--header 'X-Client-Id: YOUR_CLIENT_ID' \
--header 'Content-Type: application/json' \
--data '{"from": "+13055550123", "to": [{"name": "Ana", "number": "+13055550001"}, {"name": "Luis", "number": "+13055550002"}], "text": "Our office is closed Monday.", "sendDate": "07/05/2027 12:00"}'
sendDate uses day, month, year and a twenty-four hour time, as in the example above. Omit it to send right away. /integrations/sms/groups also answers GET to list your campaigns, and /integrations/sms/groups/GROUP_ID returns one of them with its detail.
Group requests also accept medias; provide text or at least one media attachment. When reviewing a group, check each entry in data.report: sentAt, recipient, status, errorCode, errorMessage and errorExplanation. One campaign can have different outcomes for different recipients.
Good practice
- Send only to people who agreed to hear from you, and act on a reply asking to stop. Messaging traffic from a business number is registered with the carriers, and complaints put that registration at risk.
- Keep one credential per system, and revoke rather than share.
- Retry a failed send with a growing delay. Do not loop immediately, and never resend blindly, or a recipient gets the same text twice.
- Store the message identifier and the recipient together so support questions are answerable later.
- Test against your own phone before pointing anything at a customer list.
Calls have their own guide: Sync Your Calls with the API.
Need help?
Call/Text/WhatsApp: (833) 966-4835
Email: info@zonitel.com