Capabilities

What each line can do, why a command can be accepted and then fail as unsupported, and how to tell the capability failure codes apart.

Feature-detect on GET /v1/whoami

lines[].capabilities on GET /v1/whoami lists what each of your lines can do — the command types it will carry, plus platform facts such as handle_check and receipts — and it is the list to branch on. A command can still be refused by the line after a 202, so keep the code that handles the failure below.

What failure looks like

The capability check happens on the way to the line, not at the API boundary. So a command requesting something your line cannot do still returns 202:

202 Accepted
{ "commandId": "cmd-1", "status": "queued", "disposition": "queued" }

and then settles as failed on the response stream with a capability errorCode:

event: command
{
  "commandId": "cmd-1",
  "logicalActionId": "order-8842-confirmation",
  "status": "failed",
  "errorCode": "capability_not_negotiated",
  "conversationId": "a0000000-0000-4000-8000-000000000001",
  "failureClass": "capability"
}

Telling the codes apart

capability_not_negotiated — the line cannot do this operation at all. Retrying is pointless; the identical request will fail identically until the line is updated. Do something the line can instead: a short text reply in place of a tapback, or a one-to-one message to each person in place of a group. A chat_background.set or a chat_background.remove settles this way on a line that cannot set, or cannot remove, a background — a line can carry one without the other.

capability_constraint_violation — the line can do the operation, but not with a parameter in your request: a tapback's remove: true, for example, or a reaction outside the set the line declares, or a group.update that adds or removes a member on a line that cannot change a group's members. The operation is supported; this variant of it is not. Change the request, not the timing.

invalid_session_capabilities — a fault on the line's side rather than in your command. Treat it as transient, back off, and escalate if it persists.

unsupported_capability — the line declined the operation when it ran it, after the 202. Handle it the same way as capability_not_negotiated: do not retry unchanged.

None of the four is visible at request time — the 202 looks the same in every case — which is the practical argument for building a fallback path rather than probing. When a tapback, name_photo.share or group.create settles with a capability code, say it in plain text instead; a message.send of text alone needs no content capability, so the reader gets the message either way.

On this page