Statboy agent guide
Statboy is an iPhone app that shows its user dashboards, and alerts that arrive as push notifications. It has no editing screens: everything in it is sent by agents like you. This page is for agents. It is also served as Markdown at /agents.md.
Connecting
The user gives you a connect code, such as STAT-7Q4K-92XM-H3TD, in the prompt they copied from the app. That code is your key: send it as a Bearer token on every request. The first request that uses it connects you. Call connect first, with a short name that says what you do for the user, such as finance-agent. Statboy shows that name next to everything you send. Until you have a name, only connect and whoami work.
The code connects one agent. If Statboy says it has expired or was already used, ask the user to copy a fresh prompt from the Statboy app.
The MCP server at https://statboy.ai/mcp is not available yet; requests to it return a JSON error pointing here. Use the HTTP API below.
HTTP quick start
Every action is POST https://statboy.ai/api/v1/<action> with a JSON object as the body and the connect code as a Bearer token.
curl -sS https://statboy.ai/api/v1/connect \
-H "Authorization: Bearer STAT-XXXX-XXXX-XXXX" \
-H "Content-Type: application/json" \
-d '{"name": "finance-agent"}'
curl -sS https://statboy.ai/api/v1/send_alert \
-H "Authorization: Bearer STAT-XXXX-XXXX-XXXX" \
-H "Content-Type: application/json" \
-d '{"title": "Statboy is connected", "summary": "Test alert from finance-agent."}'
curl -sS https://statboy.ai/api/v1/replace_dashboard \
-H "Authorization: Bearer STAT-XXXX-XXXX-XXXX" \
-H "Content-Type: application/json" \
-d '{"dashboard_key": "revenue", "name": "Revenue", "cards": [
{"card_key": "mrr", "type": "stat", "label": "MRR", "value": 48214,
"format": {"style": "currency", "currency": "USD"},
"change": {"direction": "up", "amount": "4.1%", "period": "in 30 days"}, "better_when": "higher"},
{"card_key": "mrr-trend", "type": "line_chart", "title": "MRR", "caption": "30 days",
"points": [{"at": "2026-10-14", "value": 46312}, {"at": "2026-11-13", "value": 48214}]}]}'
curl -sS https://statboy.ai/api/v1/whoami \
-H "Authorization: Bearer STAT-XXXX-XXXX-XXXX" -d '{}'
Actions
connect
Finishes connecting by naming this agent. Call it first: until you have a name, only connect and whoami work. The name is shown to the user next to everything you send, so pick a short one that says what you do for them, such as "finance-agent". Lowercase letters, digits and hyphens, up to 32 characters. Calling it again with the same name is safe. A connection is named once; a different agent needs its own connect code from the Statboy app.
| Field | Required | Rule |
|---|---|---|
name |
Yes | Your name, such as "finance-agent". |
whoami
Tells you who you are in Statboy: your agent name, your organization, what you are allowed to do, and how much of each limit is left. Takes no input.
No input.
list_dashboards
Lists every dashboard in the order the Dashboards tab shows them, with its key, name, stale-after period, when its data was last updated and by which agent, whether it is stale now, and its card keys in order. Takes no input.
No input.
get_dashboard
Returns one dashboard with its cards and their current data, so you can see what is there before changing it. Each card is in the form you send it, plus `info` with updated_at, updated_by and, for a stat, history_points. The cards list can be edited and sent back to replace_dashboard as it is.
| Field | Required | Rule |
|---|---|---|
dashboard_key |
Yes | 1 to 40 lowercase letters, digits, hyphens and underscores, starting with a letter or digit |
replace_dashboard
Sends a complete dashboard: the normal way to build or refresh one. It creates the dashboard if needed and makes its cards match `cards` exactly, in that order, in one step that applies completely or not at all. A card that is on the dashboard but missing from `cards` is deleted with its history, so send every card you want to keep (read them first with get_dashboard). Every card you send counts as freshly updated. Each card is an object with card_key, type (stat, line_chart, bar_chart or text) and that type's fields; the full rules are at https://statboy.ai/agents#cards. At most one stat may have headline true; it is the number shown on the Dashboards tab, and without one the first stat is used.
| Field | Required | Rule |
|---|---|---|
dashboard_key |
Yes | The dashboard's key, such as "revenue". A new key creates a dashboard. |
name |
No | Up to 40 characters. Required when the dashboard is new. |
stale_after_minutes |
No | Minutes before the dashboard counts as stale: 5 to 129600 (90 days), or "never". A new dashboard gets 1440 (24 hours). |
cards |
Yes | 0 to 30 cards, in display order. |
set_dashboard
Creates an empty dashboard, or changes a dashboard's name or stale-after period, without touching its cards. It does not make the dashboard's data count as fresh. A new dashboard goes to the end of the Dashboards tab.
| Field | Required | Rule |
|---|---|---|
dashboard_key |
Yes | 1 to 40 lowercase letters, digits, hyphens and underscores, starting with a letter or digit |
name |
No | Up to 40 characters. Required when the dashboard is new. |
stale_after_minutes |
No | Minutes before the dashboard counts as stale: 5 to 129600 (90 days), or "never". A new dashboard gets 1440 (24 hours). |
reorder_dashboards
Sets the order of the Dashboards tab. List every dashboard key exactly once, first to last.
| Field | Required | Rule |
|---|---|---|
dashboard_keys |
Yes | Every dashboard key, in the order to show them. |
delete_dashboard
Deletes a dashboard, its cards and their history at once. It cannot be undone, and the app does not ask the user first.
| Field | Required | Rule |
|---|---|---|
dashboard_key |
Yes | 1 to 40 lowercase letters, digits, hyphens and underscores, starting with a letter or digit |
set_card
Creates or replaces one card on a dashboard that already exists, leaving the other cards alone. A new card goes to the end unless before_card_key says where; an existing card keeps its place unless before_card_key is given. Replacing a stat with another type, or a number with text, deletes the stat's history. A stat sent with headline true becomes the dashboard's only headline. The card rules are at https://statboy.ai/agents#cards.
| Field | Required | Rule |
|---|---|---|
dashboard_key |
Yes | 1 to 40 lowercase letters, digits, hyphens and underscores, starting with a letter or digit |
card |
Yes | A card: card_key, type (stat, line_chart, bar_chart or text) and that type's fields. See https://statboy.ai/agents#cards. |
before_card_key |
No | Optional. Place the card just before this one. |
update_stat
Replaces a stat card's value and change, and records the value in its history: the cheapest call for a script that tracks one number. `change` and `display` are cleared when you leave them out. A stat holding a number cannot be turned into text here, so its history is never lost by accident; use set_card for that.
| Field | Required | Rule |
|---|---|---|
dashboard_key |
Yes | 1 to 40 lowercase letters, digits, hyphens and underscores, starting with a letter or digit |
card_key |
Yes | 1 to 40 lowercase letters, digits, hyphens and underscores, starting with a letter or digit |
value |
Yes | A JSON number, or text of up to 12 characters for a state such as "Healthy". |
change |
No | |
display |
No | one line of text that is not only spaces |
reorder_cards
Sets the order of a dashboard's cards. List every card key on the dashboard exactly once, first to last.
| Field | Required | Rule |
|---|---|---|
dashboard_key |
Yes | 1 to 40 lowercase letters, digits, hyphens and underscores, starting with a letter or digit |
card_keys |
Yes | Every card key, in the order to show them. |
delete_card
Deletes one card and its history. It cannot be undone, and the app does not ask the user first.
| Field | Required | Rule |
|---|---|---|
dashboard_key |
Yes | 1 to 40 lowercase letters, digits, hyphens and underscores, starting with a letter or digit |
card_key |
Yes | 1 to 40 lowercase letters, digits, hyphens and underscores, starting with a letter or digit |
send_alert
Sends an alert to everyone in the organization. It arrives on their iPhone as a push notification and stays in the app's Alerts feed. It cannot be edited or deleted afterwards. Severity sets how it arrives: info is silent, warning makes a sound, critical is time-sensitive and gets through most Focus modes. Send only what the user would want to be interrupted for. To make a retried script safe, give a repeat_key: a second alert from you with the same repeat_key within 24 hours is not sent, and the first alert is returned with duplicate true. Limits: 6 alerts a minute per agent, and 30 an hour and 100 a day per organization.
| Field | Required | Rule |
|---|---|---|
title |
Yes | Up to 60 characters. The notification's title. |
summary |
Yes | Up to 180 characters. The notification's text and the feed's summary. |
severity |
No | info (default, silent), warning (sound) or critical (time-sensitive). |
repeat_key |
No | Optional. A second alert from you with this key within 24 hours is ignored. |
list_alerts
Lists alerts sent to the organization by any agent, newest first, so you can check what was already said before sending more. Pass next_before_alert_id from one page as before_alert_id to get the next.
| Field | Required | Rule |
|---|---|---|
limit |
No | 1 to 50, default 20. |
before_alert_id |
No | Only alerts older than this one. |
Cards
A dashboard is an ordered list of up to 30 cards; an organization has up to 50 dashboards. Every card has a card_key (unique on its dashboard) and a type. Keys are 1 to 40 lowercase letters, digits, hyphens and underscores. Sending content under an existing key updates it; a new key creates it, so a script can send the same keys every run. Statboy lays cards out itself: two stats side by side, everything else full width.
- stat:
label(required, up to 24 characters);value(required: a JSON number, or text up to 12 characters such as "Healthy"; never a number in quotes);format(style:plain,currencywithcurrencysuch as "USD",percentwith the number people read, so 4.1 shows as 4.1%, orunitwithunitup to 6 characters;decimals0 to 6);change(directionup, down or flat;amountup to 10 characters such as "4.1%";periodup to 20 characters such as "in 30 days");better_when(higher,lowerorneither, which colours the change);display(up to 12 characters, replaces Statboy's formatting);headline(true for the stat shown on the Dashboards tab; at most one per dashboard);keep_history(default true for numbers). Statboy records a numeric stat's value each time you send it, at most one value a minute. - line_chart:
title(required, up to 32);points(required, 2 to 400 objects ofatandvalue, in time order;atis a date such as "2026-11-13" or a date and time with an offset, all in the same form);caption(up to 16, such as "30 days");format;description(up to 200, read by VoiceOver). - bar_chart:
title(required, up to 32);bars(required, 1 to 24 objects oflabelup to 10 characters,value0 or more, andhighlighttrue to emphasise it);caption;footnote(up to 24);format;description. - text:
body(required, up to 1,500 characters);title(up to 40). The body may use paragraphs, bold, italics, bulleted and numbered lists, links andinline code, and nothing else: headings, images, tables, quotes, code blocks, nested lists and HTML are rejected with the line they are on.
A dashboard is stale when no card data has arrived for stale_after_minutes (default 1440, or "never"); the app then shows it greyed with an amber badge. Sending the same values again keeps it fresh. Renaming, reordering and deleting do not.
Limits: 1,000 dashboard changes per organization per hour. Every successful dashboard or card action counts as one, so send whole dashboards with replace_dashboard rather than one card at a time when you can.
Responses
connectandwhoamireturnagent(name;kind:connectionfor a connect code,tokenfor an API token;permission:full,alerts_and_dataoralerts_only;expires_at, null for a connection),organization(name),can,limitsandguide.canlists what this credential may do:read,send_alerts,change_dashboardsandmanage_tokens(for API token actions, coming soon).send_alertreturnsalert_id,sent_at,duplicate(true when an earlier alert with the samerepeat_keywas returned instead),devices_notified(how many of the organization's iPhones have notifications turned on) andremaining(each alert limit'smaximumandremaining).list_alertsreturnsalerts, newest first, each withalert_id,title,summary,severity,body(longer text; null for now),link(the dashboard and card an alert opens; null for now),repeat_key,sent_byandsent_at, plusnext_before_alert_idfor the next page, or null.- Alert IDs are unique across Statboy, not counted per organization, so the first alert you send may not be 1.
Limits
- Alerts: 6 a minute per agent; 30 an hour and 100 a day per organization. An alert over a limit is rejected, not queued.
- Requests: 300 a minute per credential.
- Request body: 1 MB.
Errors
An error is a JSON object with a stable code and a message that says what to do. Fix what it says and try again.
{"error": {"code": "invalid", "message": "The `title` is 75 characters; the limit is 60.", "problems": [...]}}
| Code | HTTP |
|---|---|
unauthenticated | 401 |
connect_code_invalid | 401 |
revoked | 401 |
expired | 401 |
forbidden | 403 |
name_required | 409 |
name_taken | 409 |
already_connected | 409 |
not_found | 404 |
invalid | 422 |
limit_reached | 409 |
rate_limited | 429 |
unknown_action | 404 |
too_large | 413 |
internal | 500 |