Skip to main content
SMS logs lists transactional SMS. OTP logs lists every OTP from the workspace. Both show 25 rows per page, in the workspace timezone. The API timestamps are UTC. Anyone with logs.read can open them. Every role has that permission. See Team.

Filters

Both pages filter the same way. The choices live in the address, so a refresh keeps them. Reset clears the status and the phone search. A link that includes the message id opens that row’s drawer even when the message is older than the first page. Closing the drawer takes the id back out of the address. The empty state points at the overview, which is where a first test is sent. See Test send.

Statuses

The badge is the message status. The drawer adds a timeline. A hop appears only when its time is known. A failed or blocked hop includes a stable reason and a refunded flag read from the credit ledger. SMS statuses you can filter: OTP statuses you can filter: An OTP timeline can also show delivered when that time is known. Delivered is not one of the OTP filter chips. Reason tokens on a hop: refunded: true means the credit ledger has the refund. Do not infer a refund from the status alone.

Retries

A retry is another attempt at the same message after the network confirms it failed. The body stays the same. The customer is charged once. The extra attempt uses the other route on that destination, when there is one. Retries are an operator switch. A fresh install ships with them off (message_retry_enabled is false). While they are off, a failed delivery is failed, and the refund rules for that failure apply. There is no customer control to turn retries on. When an operator has turned them on:
  • The failure has to arrive inside the window, measured from when the message was created. The packaged window is 2 minutes. An operator can set it from 15 seconds to 10 minutes.
  • The packaged extra-attempt count is 1. The ceiling is 5.
  • A destination with a single route is not retried. There is no other route to try.
  • An OTP is retried only while the code is still unexpired. Re-sending an expired code is refused.
  • Attempts alternate between the two routes.
Do not tell a customer a failed send will retry. Say it retries only when that switch is on, inside the window, and a second route exists.

Debug a failed first send

A first send uses real credits and a real phone. A new account has 0 credits until the first successful top-up. Marketing content is blocked with 403 content_blocked. Transactional SMS without the workspace’s own approved sender ID returns 422 sender_id_required. Work down this list.
  1. Did the API accept it? If the overview or the API returned an error and the logs have no row, match error.type. Nothing was charged for these refusals: The full list is on Errors.
  2. Find the row. Open SMS logs or OTP logs. Filter Failed. Search the phone. Open the row. If the first test was an OTP, start with OTP logs. The overview test card sends an OTP.
  3. Read the timeline. Use the reason table above. delivery_failed means the network reported it undelivered. send_failed means we did not hand it on. refunded tells you whether the credit came back.
  4. Check the phone and the balance again before you send a second test. A second test spends credits again. It is a new message, not a free replay of the first.
  5. Still stuck. Open a ticket from Support with the message id, the phone, and the time. Do not paste API keys. See Support tickets.