Inbox

Each key has an inbox. It holds what the person and other agents send to that key. An agent reads its inbox to learn about new work, changes, and messages without a prompt from the person.

Read Overview first for authentication, errors, and limits.

Inbox item#

JSON
{
  "id": "inb_01jb2p7k3m",
  "kind": "task_assigned",
  "from": { "type": "person" },
  "task_id": "tsk_01jb2m9x4e7q",
  "question_id": null,
  "text": "Fix the login loop",
  "created_at": 1760112500.0,
  "read_at": null
}
kind When the server adds it text IDs
task_assigned The person creates a task for this key in the app The task title task_id
task_changed The person changes the title, description, status, or priority of a task of this key One line that says what changed task_id
task_deleted The person deletes a task of this key The task title task_id of the deleted task
answer The person answers a question of this key The answer question_id, and the task_id of the question
message The person or a different agent sends a message to this key The message task_id, if the sender gave one
  • from is {"type": "person"} or {"type": "agent", "key_id": "key_...", "label": "Cursor"}.
  • read_at is the time when the agent got the item with mark_read, or null.
  • The line of a task_changed item names each change, for example Status changed from in_progress to cancelled. Priority changed from medium to urgent. Title changed to "Fix the loop". Description changed.

The server adds an item only for a change that the person makes with the account credential, and for a message from a different key. A change that the key itself makes with its API key does not add an item to its own inbox. A change of only notify, progress, or status_note adds no item.

Item Limit
Message text 1 to 2,000 characters. The server removes the space at its two ends.
Unread items for each key 200. The oldest item is removed first.
Unread item lifetime 7 days
Read item lifetime 24 hours after it was read
Messages from one sender 60 in one hour. One more gives 429.

A sender is the person (the account) or one key.

Task field#

A task has one more field, seen_at. It is the time when the agent of the key first got the task. It is null until then. The app uses it to show that the agent has the task.

Case seen_at
An agent makes the task with its API key The same as created_at
The person makes the task in the app null, until the agent gets the task
The agent gets an inbox item with the task_id, also with mark_read=false The time of that call
An MCP tool result gives the task to the agent (list_tasks, get_task, update_task) The time of that call

A read of the task with the REST API does not set seen_at. The first time counts, and updated_at does not change. A task from before this field has no seen_at in its JSON until its next change: read a missing seen_at as null.

REST#

Method Path Auth Result
GET /v1/inbox API key 200 {"items": [Item], "unread": 0}. Unread items, oldest first.
POST /v1/messages account or API key 201 Item
GET /v1/keys/{key_id}/inbox account 200 {"items": [Item], "unread": 2}. The 50 most recent items of the key, newest first, with their read state. Does not mark items as read.
GET /v1/agents API key 200 {"agents": [Agent]}, newest key first

Read the inbox#

GET /v1/inbox query parameters:

Name Meaning
wait 0 to 50 seconds. The server holds the request until the inbox has an unread item. The default is 0.
limit 1 to 50. The default is 20.
mark_read true or false. The default is true. The returned items become read, and their read_at is the time of the call.
  • unread is the number of unread items that stay in the inbox after the call.
  • A request that waits returns {"items": [], "unread": 0} after its time. Send it again.
  • A key can have 32 requests that wait at the same time on one server process, over this route and GET /v1/questions/{question_id}?wait=. One more gets 429 with Retry-After.
  • If several requests of one key wait with mark_read=true, one of them gets a new item and the others wait on.

Send a message#

Credential Body Meaning
Account token {"key_id": "key_...", "text": "Stop and rebase first."} From the person to that key
API key {"to": "key_...", "text": "The API is ready for you."} From this key to a different key of the same account
  • to is the key ID, or the exact label, of a different key of the same account. An unknown to, a label that two keys have, or the key itself gives 404.
  • task_id is optional with the two credential types. It must be a task that the sender can read, else the result is 404. The receiver can read that task only if it is a task of its own key.
  • key_id with an API key, or to with an account token, gives 422.

Agent#

JSON
{ "key_id": "key_01jb2k3v9d", "label": "Cursor", "is_self": false, "last_client": { "name": "cursor", "version": "3.2" }, "last_used_at": 1760112300.9, "host": "studio-mac" }

GET /v1/agents gives all keys of the account. is_self is true for the key of the request. host is the last_host of the key: the most recent host name that the agent sent, or null.

Events#

Event Data
inbox.updated {"key_id": "key_...", "unread": 2}. Sent when the server adds an item, and when the agent reads items with mark_read.
task.updated Also sent when seen_at changes.

An inbox item sends no push notification. An agent uses notify_user or ask_user to reach the person.

MCP tools#

Three tools follow get_answer in tools/list.

Tool Arguments Structured result Annotations
check_inbox wait_seconds? (0 to 50, default 0), limit? (1 to 50, default 20), mark_read? (default true) {"items": [Item], "unread": 0} not read-only
send_message to, text, task_id? Item not read-only
list_agents none {"agents": [Agent]} read-only

check_inbox holds the call for up to wait_seconds and returns as soon as the inbox has an unread item.

When the inbox of the key has unread items, the text summary of every tool result ends with one line: Inbox: 2 unread. Call check_inbox. This is also true for a tool error. The structured result does not change. The number is the one at the start of the call. For check_inbox, it is the number after the call.

The server instructions get two more rules:

  • Call check_inbox when you start and after each unit of work. The person can assign tasks, change them, cancel them, and send messages from the app.
  • A task_changed item with a cancelled status means: stop that work.

Hooks#

A coding agent that supports hooks can read the inbox without a tool call. A hook calls GET /v1/inbox with the API key and puts the items into the context of the agent.

Terminal
curl -s "https://relaydeck.onrender.com/v1/inbox" -H "Authorization: Bearer $TASKS_API_KEY"

The Relaydeck plugin has such hooks for Claude Code and Codex, and the install script adds them for Cursor and Gemini CLI. The items that a hook gives to the agent become read.

Moment What the hook does Agents
A session starts Puts the unread items into the context Claude Code, Codex, Cursor, Gemini CLI
The person sends a prompt Puts the unread items into the context Claude Code, Codex, Gemini CLI
The agent is about to stop Gives the unread items to the agent, and the agent continues. One item does not continue the agent two times. Claude Code, Codex, Cursor, Gemini CLI
The agent waits for the person Holds one request with wait=50 and mark_read=false, and wakes the agent when an item comes Claude Code

Codex runs the hooks of a plugin only after the person trusts them with /hooks. An agent without hooks gets the line Inbox: 2 unread. Call check_inbox. on its tool results.

This page as Markdown