Frames and replies
Every call over the socket is one JSON frame in and one JSON frame out.
The request frame
Code
funnames the operation. Every fun starts with/app/.msgidis yours to choose, and it is required. The reply echoes it back. Send a frame without it and you get400.dataholds the fun's parameters. Omit it, or send{}, for a fun that takes none.
Phone funs take the phone's slot in data. Get it from /app/phones/list or from the
phones list in the connect reply.
The success envelope
A successful call replies with the same status and body the matching REST endpoint returns:
Code
status is 200 for a read, 201 for something created, 202 for work accepted and queued
on a phone, 204 for a delete (with data as null).
The error envelope
A failed call replies with message in place of data, and adds errors when the failure
was a validation failure:
Code
errors maps each rejected field to its messages. Read message for the summary.
Match on msgid, not on order
Calls run independently. With several in flight, replies can come back in any order, and
events arrive in between. Keep a table of the ids you are waiting on and
match each reply on msgid.
A frame with no msgid at all is an event, not a reply.
Code
Status codes
| Status | What caused it |
|---|---|
400 | The frame is malformed: no msgid, a data that is not an object, or a phone fun with no slot. |
403 | Your token lacks the ability this fun needs, the API token behind the connection was revoked or expired, or the slot names a phone you cannot view or control. |
404 | The fun does not exist, or the record you named does not exist or is not yours. |
409 | A conflict: cancelling a submission that already finished, or deleting one that is still in flight. |
422 | Validation failed. Read errors for the fields. |
429 | You passed the screen-read cap. Screen reads are limited to 60 a minute, and message says how many seconds to wait. |
502 | A phone could not be reached, or a screen read could not be completed. |
503 | The capability is not ready yet. Agent runs return this when the phone agent is not available. |
500 | Something unexpected went wrong. Retry, and quote the call if it persists. |
401 never appears in a fun reply. It belongs to the REST call that mints the socket URL: a
missing or invalid API token stops you before you connect. See
Connecting.
A 404 on a record you believe exists usually means it is not yours. Accounts and
submissions are scoped to your account, so "not found" and "not yours" read the same.
Limits
Frames are not counted against the REST rate limit. The one cap that applies is on screen
reads: 60 a minute per account, shared between /app/phones/ocr, the REST screen-read
endpoint and the MCP tool. Over that you get 429.
Next
- Phones: the phone funs and their
datafields. - Accounts, Submissions and Billing: the rest of the funs.
- Events: frames that arrive without a
msgid.

