HTTP API
The plain-JSON endpoints behind every surface — for programs without an MCP client.
Everything the MCP tools and the CLI do bottoms out in plain HTTP + JSON. Use the API directly when the caller is a server, a webhook, a cron job, or any program where an MCP client or the CLI doesn't fit.
Authentication by endpoint
The API splits cleanly along the trust boundary:
- Management endpoints (
/api/rects,/api/view-sources,/api/rect-instances) operate on your account's templates and instance lists. Call them authenticated: with a browser session, or anAuthorization: Bearer <token>header carrying an account API token from account settings. The CLI sendsRECT_API_TOKENthis way in CI. - Capability endpoints (
/api/rect/<instanceId>/…) operate on one live instance. They are unauthenticated by design: the opaque instance id is the capability, the same property that lets a human open the view from just a link. Treat instance ids like the secrets they are. - Template discovery (
/api/rects/search) is public for public templates. A browser session or bearer token also includes templates visible to that caller;accountIdnarrows results to a workspace the caller can access.
Discover templates
curl -X POST https://rect.sh/api/rects/search \
-H 'content-type: application/json' \
-d '{ "query": "project planning dashboard", "limit": 10 }'Returns ranked compact candidates in results. Fetch the selected template's
full spec before issuing it; MCP uses rect_get_spec and the CLI uses
rect spec.
{
"results": [
{
"rectId": "…",
"name": "Project Board",
"slug": "project-board",
"description": "Plan and track project work.",
"owner": {
"accountId": "…",
"name": "rect.sh",
"slug": "official"
},
"source": "official",
"score": 0.039
}
]
}score is PostgreSQL full-text relevance and determines result order.
Keyword-based search matches words and phrases across each template's name,
slug, description, actions, and state fields. The default limit is 10 and the
maximum is 20; query must contain 1–1000 characters after trimming. Invalid
input returns 400, unauthorized or inaccessible accountId values return
401 or 403, and a temporarily unavailable search dependency returns 503.
Drive an instance (capability)
The endpoints a running loop actually touches. <id> is the instance id from
issuing (also visible in the capability URL /r/<id>).
| Endpoint | Method | What it does |
|---|---|---|
/api/rect/<id>/check | GET | Latest view model + revision. |
/api/rect/<id>/state | PATCH | Apply a merge patch: { patch }. |
/api/rect/<id>/dispatch | POST | Run a named action: { action, input? }. |
/api/rect/<id>/attachments/uploads | POST | Create a signed attachment upload ticket. |
/api/rect/<id>/attachments/<attId>/complete | POST | Complete a signed upload. |
/api/rect/<id>/attachments/<attId>/<fileName> | GET | Download an attachment's bytes. |
Read the current state:
curl https://rect.sh/api/rect/<id>/checkEvery read and write returns the same instance envelope:
{
"instanceId": "…",
"template": "client-intake",
"name": "Acme Corp — intake",
"status": "open",
"revision": 7,
"viewUrl": "https://rect.sh/r/…",
"checkUrl": "https://rect.sh/api/rect/…/check",
"stateUrl": "https://rect.sh/api/rect/…/state",
"dispatchUrl": "https://rect.sh/api/rect/…/dispatch",
"viewModel": { "…": "…" }
}Patch it (RFC 7386 — objects deep-merge, null deletes, arrays replace):
curl -X PATCH https://rect.sh/api/rect/<id>/state \
-H 'content-type: application/json' \
-d '{ "patch": { "note": "reviewed" } }'Patches apply against the latest state — concurrent writes are re-merged
server-side, so no revision bookkeeping is needed. Writes to reserved
namespaces ($attachments) return 400 with code: "reserved_key".
Dispatch a named action:
curl -X POST https://rect.sh/api/rect/<id>/dispatch \
-H 'content-type: application/json' \
-d '{ "action": "approve" }'Status codes map to the dispatch result codes:
200 ok, 400 no_actions / unknown_action / invalid_input /
reserved_key, 409 conflict, 413 too_large, 422 rejected (the
handler's ctx.reject, with its rejectCode), 500 runtime_error /
timeout.
Issue an instance
curl -X POST https://rect.sh/api/rects/<rectId>/instances \
-H 'content-type: application/json' \
-d '{ "name": "Acme Corp — intake", "viewModel": { "company": "Acme" } }'Returns 201 with the instance envelope — viewUrl is what you hand the
human. viewModel is optional; omitted, the instance starts from the
template's example. Knowing a template's id is what authorizes issuing from
it.
Manage templates & instances (authenticated)
| Endpoint | Method | What it does |
|---|---|---|
/api/rects | GET | List an account's templates. |
/api/rects | POST | Register (or update) a template: point it at an uploaded view source, upserted by (account, slug). |
/api/rects/<rectId> | DELETE | Delete a template. |
/api/rects/<rectId>/remix-source | GET | Download a template's remix source. |
/api/view-sources/uploads | POST | Request a signed upload for a compiled bundle (.html / .zip, ≤ 20 MB). |
/api/view-sources/<sourceId>/complete | POST | Finalize an upload — extracts and validates the spec and actions blocks. |
/api/rect-instances | GET | List issued instances. |
/api/rect-instances | PATCH | Update instance metadata (name). |
curl https://rect.sh/api/rects \
-H "authorization: Bearer $RECT_API_TOKEN"These are the endpoints rect publish, rect list, and rect find are built
on — for publishing from your own machine or CI, the CLI is
almost always the better interface.
MCP transport
The MCP server itself is one more HTTP endpoint:
| Endpoint | Method | What it does |
|---|---|---|
/api/mcp/rectsh | GET (no event-stream Accept) | JSON info doc: tool list + HTTP fallbacks. |
/api/mcp/rectsh | POST / GET / DELETE | The streamable-HTTP MCP transport. |