textbee Logotextbee.dev
Save 44% with yearly billing.View Plans
Documentation

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:

Shell
curl https://api.textbee.dev/api/v1/gateway/stats \
  -H "x-api-key: YOUR_API_KEY"

Fix

StatusMeaningFix
400No enabled device found. Enable a device or pass a deviceId.Open the app on the phone and turn on Gateway Enabled in Settings.
400Device does not exist or is not enabledThe deviceId you passed points at a disabled device. Turn on Gateway Enabled in the app on that phone, or leave deviceId out.
400Please verify your email to continueOpen the verification email from textbee and click the link. Sending needs a verified email.
400Failed to send SMSThe push to the phone failed. See check 8.
400Invalid recipients or Message cannot be blankSend recipients as an array of E.164 numbers, for example ["+12015550123"], and a non-empty message.
400scheduledAt must be a future dateSend a future time in ISO 8601 with a timezone. See Scheduled messages.
401The API key is missing, invalid or revokedSend the x-api-key header. Create a new key in the dashboard if needed. See API keys.
404Device not foundThe deviceId is not on your account. List your devices with GET /gateway/devices.
429A plan limit is used upThe 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:

Shell
curl https://api.textbee.dev/api/v1/gateway/devices \
  -H "x-api-key: YOUR_API_KEY"

For the device that sends, check two fields:

FieldGood value
enabledtrue
lastHeartbeatWithin 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

  1. On the phone, open the textbee app and check that Gateway Enabled is on in Settings.
  2. Check the phone's internet connection.
  3. Go to Settings > Device health and tap Send heartbeat. The row should change to a recent time.
  4. 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:

Shell
curl "https://api.textbee.dev/api/v1/gateway/messages?smsBatchId=YOUR_BATCH_ID" \
  -H "x-api-key: YOUR_API_KEY"
What you seeMeaning
dispatchDueAt is in the futureThe message waits on the server. It is scheduled, or it is part of a large batch released in waves.
dispatchedAt is set, pushReceivedAt is emptyThe push left textbee, but the phone did not get it. The phone is asleep or offline.
pushReceivedAt is set, sendAttemptedAt is emptyThe 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 estimatedCompletionAt for large batches.
  • Scheduled message: the message sends at its scheduledAt time. 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

errorCodeAndroid constanterrorMessageWhat 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 sent forever 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 the UNKNOWN_STATE webhook 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:

Shell
curl "https://api.textbee.dev/api/v1/gateway/messages?direction=sent&status=failed&limit=100" \
  -H "x-api-key: YOUR_API_KEY"

Fix

  1. Increase the Send Delay in the app settings. A longer gap keeps the phone under the cap.
  2. Split large batches and send them over a longer time.
  3. Spread the load over more than one phone. See Devices.
  4. 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 errorCode that starts with FCM_, for example FCM_TOKEN_NOT_REGISTERED.
  • lastHeartbeat does 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.

Next steps