Skip to main content

Conversations

A conversation is a text thread between one of your numbers and one other party. It is how the message center groups messages, and it has a resolved state your team works through — the portal's "Unresolved" filter. You can read the messages in one, and change the thread's state around them.

:::info A conversation has no id It is identified by both numbers: your line, and the other party. That is why these endpoints take two path segments instead of an id.

If you are reacting to an AccountSMS webhook you already have both numbers, so you can act immediately with no lookup first. :::

Formatting in the path is fine — +1 (212) 555-0188 works — and the response echoes the normalized digits, so you can see what was actually addressed.

Resolving

curl -X POST \
https://api.account.telebroad.com/api/public/v1/sms/conversations/12125550188/13475550123/resolve \
-H "Authorization: Bearer $TB_KEY"

No body required — a bare POST is a complete request.

Two behaviours to rely on:

  • It works on threads nobody has touched. Most conversations have no stored state until someone actions them. Resolving one creates that state rather than returning 404, so you can close a fresh inbound thread your integration handled elsewhere. An endpoint that 404'd here would fail on the common case.
  • It is idempotent. Resolving an already-resolved conversation returns 200 with the stored state and does not re-stamp who closed it or when. Retrying after a timeout cannot rewrite history.

Who gets credited

CredentialresolvedBy
OAuth tokenAlways its own owner. You cannot name someone else.
API keyAbsent, unless you pass resolvedBy explicitly.

resolvedBy is absent — not 0 — when an integration resolved a thread with no person named. A key has no user, and a 0 there would read as a real id.

A resolvedBy that is not a user on your account is a 400.

Reading a conversation

curl 'https://api.account.telebroad.com/api/public/v1/sms/conversations/12125550188/13475550123' -H "Authorization: Bearer $TB_KEY"

Needs messages:read — reading the contents of a conversation is a separate consent from the configuration scope, the same way call recordings are.

:::caution Reading does not mark anything read markRead defaults to false, which differs from the portal, where opening a thread clears it.

An integration polling for new messages would otherwise silently empty the unread badges your staff are working from, and nothing would explain why the inbox kept emptying itself. Pass markRead=true only when a person has actually seen the messages. :::

Read state is per user, not per account: a thread your colleague has read is still unread for you. That is why read on each message and unread on each conversation reflect your credential, and readBy lists everyone else.

The inbox

curl 'https://api.account.telebroad.com/api/public/v1/sms/conversations?unresolved=true&assignedToMe=true' -H "Authorization: Bearer $TB_KEY"

One entry per thread with its queue state already attached, so a queue view is one call rather than one per conversation. Filters combine as ANDunresolved + assignedToMe is "my open threads", the message center's default view.

Omit lines and every texting number on the account is listed, so a fresh integration does not need GET /sms/lines first and keeps working when the customer buys a number.

:::info The queue filters only see threads that have queue state unresolved, assignedToMe and unassigned are evaluated against a thread's stored state — so a thread that has never had any (never resolved, never assigned) is not returned by them, including by unassigned. It is the same set the portal's Unresolved queue shows, for the same reason.

List without those filters to see every thread. :::

Opening at a specific message

If you hold a message id — from an AccountSMS webhook, say — you do not know its position in the thread, so limit/offset cannot get you there. GET /sms/conversations/{line}/{number}/messages/{id} returns the surrounding page directly.

Assigning

curl -X POST https://api.account.telebroad.com/api/public/v1/sms/conversations/12125550188/13475550123/assign -H "Authorization: Bearer $TB_KEY" -H 'Content-Type: application/json' -d '{"userId": 481920}'

A null or absent userId unassigns, returning the thread to the unassigned queue — which is why there is no separate unassign endpoint.

Assigning is not resolving. They are independent axes: a resolved thread can stay assigned to whoever closed it, and an open thread can sit unassigned. That is what makes unresolved and unassigned separately filterable.

Reopening

POST /sms/conversations/{line}/{number}/reopen moves a resolved thread back into the open queue — the missing half of resolve, for when a customer replies to something you already closed. Idempotent, and a thread nobody ever resolved is already open, so it succeeds there too.

Deleting

DELETE on a conversation, or on one message, is permanent and has no recovery through this API. It needs messages:write.

:::danger A second gate that scopes do not override If the account has restrict deleting SMS switched on, delete answers 403 even with messages:write. That setting exists precisely so an account owner can stop their own staff and integrations from destroying message history. :::

What is missing today

:::note No resolve webhook There is no notification when a colleague resolves or assigns a thread in the portal. The AccountSMS webhook fires on messages, not on conversation state, so a client mirroring queue state has to poll the inbox.

If you need it, say so — it moves it up the list. :::

Errors

StatustypeCause
400invalid_requestA path segment is not a phone number, or an unknown body field
400invalid_requestresolvedBy / userId is not a user on your account
400invalid_requestMarking a line read with an API key — read state needs a user, so authorize with OAuth
403insufficient_scopeThe credential lacks the scope the endpoint needs
403permission_deniedline is not a number your credential is authorized for, or the account restricts deleting messages

The tenant boundary is the line, not the conversation — the other party's number is just an external phone number. It is the same check that governs POST /sms/messages, so a line you can send from is a line you can resolve on.