When you send a message, the API answers immediately with status scheduled or sent. That means "we accepted the message", not "it reached the handset". The real confirmation arrives later, from the carrier, as a callback to your address.
Setting it up
Send a callback_url in the message payload, or configure a default one on your account. Calisero will POST to that address every time the message status changes.
{
"id": "0197e8c5-2c11-72cf-8057-bca8f619bd52",
"status": "delivered",
"recipient": "+40712345678",
"delivered_at": "2026-07-16T09:41:22.000000Z"
}
Answer fast, process later
Your endpoint must return 200 within a few hundred milliseconds. Do not update databases, send emails or call other services during the request.
Write the event to a queue and return immediately. Processing happens asynchronously, in a worker. If your endpoint is slow, retries pile up and you fall hours behind.
Handle duplicates
Callbacks are delivered at least once. An unstable network, a one-second timeout or a rolling deploy can produce the same event twice.
Make processing idempotent: use the id + status pair as a unique key and ignore what you have already seen. Never assume an event arrives exactly once.
Do not assume ordering
Events can arrive in a different order than they occurred. A delivered may land before a sent. Always compare the payload timestamp against what you have stored and discard events older than your current state.
Secure the endpoint
The callback address is public. Treat it that way:
- use a hard-to-guess URL with a random identifier in the path;
- accept only
POST, and only over HTTPS; - validate that the received
idmatches a message you actually sent; - do not expose sensitive data in the response.
What to do when a callback never comes
Networks fail, servers restart. Keep a periodic job that finds messages without a final status for more than a few hours and queries the API directly for their state. The webhook is the fast path; polling is the safety net.