Messages not sending
Diagnose an SMS that textbee does not send: API errors, offline devices, permissions, messages stuck in pending, failure codes and carrier delivery.
Updated
A message that does not arrive stopped at one of four points: the API, the push to the phone, the phone, or the carrier. Work through the checks below in order. Each check says how to find the answer and what to change.
The API returns 200 when it accepts a message. Acceptance is not delivery. The message status and its timestamps show how far the message got. See Delivery status for every state.
1. Did the API accept the request?
How to check
Look at the HTTP status code and the response body of your send request. This call confirms that your API key works:
curl https://api.textbee.dev/api/v1/gateway/stats \
-H "x-api-key: YOUR_API_KEY"Fix
| Status | Meaning | Fix |
|---|---|---|
| 400 | No enabled device found. Enable a device or pass a deviceId. | Open the app on the phone and turn on Gateway Enabled in Settings. |
| 400 | Device does not exist or is not enabled | The deviceId you passed points at a disabled device. Turn on Gateway Enabled in the app on that phone, or leave deviceId out. |
| 400 | Please verify your email to continue | Open the verification email from textbee and click the link. Sending needs a verified email. |
| 400 | Failed to send SMS | The push to the phone failed. See check 8. |
| 400 | Invalid recipients or Message cannot be blank | Send recipients as an array of E.164 numbers, for example ["+12015550123"], and a non-empty message. |
| 400 | scheduledAt must be a future date | Send a future time in ISO 8601 with a timezone. See Scheduled messages. |
| 401 | The API key is missing, invalid or revoked | Send the x-api-key header. Create a new key in the dashboard if needed. See API keys. |
| 404 | Device not found | The deviceId is not on your account. List your devices with GET /gateway/devices. |
| 429 | A plan limit is used up | The body says which one: the daily limit, the monthly limit (the last 30 days) or the per-batch limit. Nothing was sent. Wait for the limit to reset, split the batch, or upgrade. See Pricing. |
A 429 on device registration or when you enable a device has a different text: Active device limit reached: your plan allows up to N active device(s).... Turn off Gateway Enabled in the app on another phone, delete an old device in the dashboard Devices panel, or upgrade your plan. Disconnect Device in the app only clears the credentials on the phone. The device stays on your account and still counts while it is enabled.
Do not retry a 429 in a loop. A retry does not reset the limit.
2. Is the device enabled and online?
How to check
List your devices:
curl https://api.textbee.dev/api/v1/gateway/devices \
-H "x-api-key: YOUR_API_KEY"For the device that sends, check two fields:
| Field | Good value |
|---|---|
enabled | true |
lastHeartbeat | Within the last heartbeatIntervalMinutes (30 minutes by default) |
A device with an old lastHeartbeat is probably offline. The API still accepts sends for it, and the messages wait until the phone comes back.
Fix
- On the phone, open the textbee app and check that Gateway Enabled is on in Settings.
- Check the phone's internet connection.
- Go to Settings > Device health and tap Send heartbeat. The row should change to a recent time.
- If the heartbeat keeps going stale, Android is stopping the app in the background. Follow Keep the phone online.
When you omit deviceId, textbee sends from your default device, or else from the enabled device with the most recent heartbeat. Check which device that is on Devices.
3. Does the app have the SMS permission?
How to check
Open Settings > Device health in the app. The SMS permissions row shows Granted, or it lists the missing permissions.
Fix
Tap Grant on the row and allow the permissions. Sending needs the Send SMS permission. The Receive SMS permission is only for forwarding incoming SMS, but the sticky notification cannot start without it. Grant all three permissions that the row lists: Send SMS, Receive SMS and Phone state.
If Android does not show the permission prompt again, open the phone's app settings for textbee and allow SMS there.
4. The message is stuck in pending
pending means textbee has the message and the phone has not reported a send yet.
How to check
Read the message and look at its timestamps:
curl "https://api.textbee.dev/api/v1/gateway/messages?smsBatchId=YOUR_BATCH_ID" \
-H "x-api-key: YOUR_API_KEY"| What you see | Meaning |
|---|---|
dispatchDueAt is in the future | The message waits on the server. It is scheduled, or it is part of a large batch released in waves. |
dispatchedAt is set, pushReceivedAt is empty | The push left textbee, but the phone did not get it. The phone is asleep or offline. |
pushReceivedAt is set, sendAttemptedAt is empty | The phone has the message and has not sent it yet. It works through a batch with the Send Delay between messages. |
Fix
- Phone asleep or offline: wake the phone, check its connection and follow Keep the phone online. The messages send when the phone comes back.
- Large batch: wait. The phone sends one message at a time, with the Send Delay from the app settings between messages. At 5 seconds, 500 recipients take about 41 minutes. The send response has
estimatedCompletionAtfor large batches. - Scheduled message: the message sends at its
scheduledAttime. There is no cancel endpoint. See Scheduled messages.
5. The message failed with an errorCode
How to check
A failed message has status: "failed", a failedAt time, an errorCode and an errorMessage. On a failure from the phone, errorCode is Android's numeric result code as a string. The errorMessage explains it in words.
Fix
errorCode | Android constant | errorMessage | What to do |
|---|---|---|---|
"1" | RESULT_ERROR_GENERIC_FAILURE | "SMS failed on device. Common causes: no SMS credit on SIM, weak signal, or carrier blocked. Check SIM balance and signal, then try again." It can end with a radio code in parentheses. | Check the SIM balance and signal. Send one test from the phone's own SMS app. Then retry. |
"2" | RESULT_ERROR_RADIO_OFF | "Mobile radio is off (e.g. airplane mode). Turn off airplane mode and ensure cellular is on." | Turn off airplane mode and turn on mobile service. |
"3" | RESULT_ERROR_NULL_PDU | "Message could not be sent; invalid format or carrier issue. Try a shorter message or different recipient." | Check for an empty body or unusual characters. Try a shorter message. |
"4" | RESULT_ERROR_NO_SERVICE | "No cellular service. Check signal and try again when you have coverage." | Move the phone to a place with coverage, or check the SIM. |
"5" | RESULT_ERROR_LIMIT_EXCEEDED | "Device/carrier send limit reached (too many SMS in a short time). Wait a few minutes or lower the send rate." | See check 7. |
"7" | RESULT_ERROR_SHORT_CODE_NOT_ALLOWED | "Short code not allowed on this carrier. Use a full phone number." | Send to a full phone number. |
"8" | RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED | "Short codes are not supported on this carrier. Use a full phone number." | Send to a full phone number. |
"17" | RESULT_NETWORK_ERROR | "Network error while sending. Check signal and try again." | Check the signal and retry. |
An errorCode that starts with FCM_ means the push to the phone failed, so the phone never got the message. See check 8.
Retry a failed message with a new send request. Check first that the recipient did not get it, because each retry is a new message against your plan.
6. The message is sent but not delivered
sent means the carrier accepted the message. delivered means the carrier sent back a delivery report.
How to check
Look for sentAt and deliveredAt on the message. A message with sentAt and no deliveredAt left the phone.
Fix
- No delivery report: many carriers do not send delivery reports. A message can stay
sentforever and still arrive. Ask the recipient. - Status
delivery_failed: the carrier's delivery report said the message was not delivered, or the report was canceled because the carrier does not support delivery receipts. The message can still have arrived in the second case. This status fires theUNKNOWN_STATEwebhook event. - Wrong number: check the number in E.164 format with the country code, for example
+12015550123. - Recipient phone off or out of coverage: the carrier holds the message for a time and delivers it when the phone comes back.
- Carrier filtering: a carrier can drop messages that look like spam. Send fewer identical messages, and increase the Send Delay.
7. Android's own outgoing SMS cap
Android limits how many SMS one app can send in a short time. When the phone hits the cap, messages fail with errorCode "5" (RESULT_ERROR_LIMIT_EXCEEDED). The cap is set by Android and the phone maker, not by textbee or your plan.
How to check
Filter your sent messages by status and look for many "5" codes close together:
curl "https://api.textbee.dev/api/v1/gateway/messages?direction=sent&status=failed&limit=100" \
-H "x-api-key: YOUR_API_KEY"Fix
- Increase the Send Delay in the app settings. A longer gap keeps the phone under the cap.
- Split large batches and send them over a longer time.
- Spread the load over more than one phone. See Devices.
- Send the failed messages again after a few minutes.
8. When to reconnect the device
Reconnect the device when a push to the phone fails and the checks above do not help:
- The send returns 400
Failed to send SMS. - Messages fail with an
errorCodethat starts withFCM_, for exampleFCM_TOKEN_NOT_REGISTERED. lastHeartbeatdoes not update after you tap Send heartbeat, and the phone has internet.- You reinstalled the app, cleared its data or restored the phone.
Open the app and register it again with the same device id. The app sends a new push token to textbee. See Reconnecting an old device.
Frequently asked questions
Why does the API return 200 when the phone is offline?
The API accepts the message and stores it. The phone gets it when it comes back online. Check lastHeartbeat before a time-critical send.
Does textbee retry a failed message?
No. A message with status: "failed" stays failed. Send a new request to try again.
Can I send faster than the Send Delay?
You can set the Send Delay to 0 in the app. The app warns: "No gap between messages. Carriers may block a phone that sends too fast." A short delay also makes Android's outgoing cap more likely.
Why do some messages in one batch fail and others send?
Each recipient is a separate message. Signal, the carrier and Android's cap act on each one. The batch shows partial_success when some succeed and some fail.