Delivery & Error Codes
Reference for SMS delivery statuses, verification session statuses, webhook events, and API error codes.
This page is the single reference for every status value and error code you may encounter when using Moorsyl. Use it to understand what happened to a message or verification session and how to react to it in your code.
SMS delivery statuses
Every SMS has a status field that progresses through the following states:
| Status | Meaning |
|---|---|
pending | Message accepted and queued, not yet picked up by a worker |
processing | A worker has claimed the message and is submitting it to the carrier |
sent | Carrier acknowledged receipt — the message is on its way to the handset |
failed | All delivery attempts exhausted; the message will not be retried |
A failed message includes an errorText field with the reason returned by the carrier or the Moorsyl worker (for example, "Carrier rejected message"). This field is also present in the sms.failed webhook event.
State transitions
pending → processing → sent
↘ failed (after max retries)A message moves from processing back to pending if the worker crashes or times out, so it can be picked up again. Once sent or failed, the status is terminal.
Verification session statuses
Every session returned by /api/verify/get has a status field:
| Status | Meaning |
|---|---|
pending | Code was sent; waiting for the user to submit it |
approved | User entered the correct code — session is now closed |
expired | Session TTL elapsed before the user submitted a valid code |
canceled | Session was explicitly canceled (for example, a new code was requested for the same number) |
approved, expired, and canceled are all terminal — a session in one of these states cannot transition further.
Webhook events
| Event | Fired when |
|---|---|
sms.sent | Carrier acknowledged the message |
sms.failed | Message permanently failed after all retries |
verify.sent | A one-time code was sent to a phone number |
verify.approved | The user entered the correct code |
verify.failed | The session expired or max attempts were exceeded |
See Webhooks for payload shapes and signature verification.
API error codes
All Moorsyl API endpoints return standard HTTP status codes. The response body always contains a machine-readable code field alongside a human-readable message.
{
"code": "UNAUTHORIZED",
"message": "Invalid or missing API key"
}| Status | Code | Meaning | Common cause |
|---|---|---|---|
400 | BAD_REQUEST | The request body is invalid | Wrong phone number format, empty message body, body over 1 600 characters, missing required field |
401 | UNAUTHORIZED | API key is missing or not recognized | Sending a request without x-api-key, or using a key that has been deleted |
402 | PAYMENT_REQUIRED | Insufficient balance | Organization balance is zero or too low to cover the message cost |
403 | FORBIDDEN | API key exists but cannot perform this action | Key is not linked to an active organization, or a publishable key was used where a secret key is required |
404 | NOT_FOUND | Resource not found | verificationId does not exist or belongs to a different organization |
429 | TOO_MANY_REQUESTS | Rate limit exceeded | Per-phone, per-org, or IP-level rate limit hit — back off and retry |
500 | INTERNAL_SERVER_ERROR | Unexpected server error | Transient — retry with exponential back-off; contact support if it persists |
Retry guidance
| Error | Retry? | Strategy |
|---|---|---|
400 BAD_REQUEST | No | Fix the request payload before retrying |
401 UNAUTHORIZED | No | Check your API key |
402 PAYMENT_REQUIRED | No | Top up your balance first |
403 FORBIDDEN | No | Check key type and organization status |
404 NOT_FOUND | No | Verify the ID is correct |
429 TOO_MANY_REQUESTS | Yes | Wait and retry with exponential back-off |
500 INTERNAL_SERVER_ERROR | Yes | Retry with exponential back-off |
For persistent issues not explained by the codes above, contact support@moorsyl.com.