Everything an external integrator needs to call the myAI gateway directly: mint a scoped API key, copy-paste curl against the REST and MCP surfaces, and the rate-limit / error-code contract to build against. Building a Zapier or n8n connector? Start here, then wire outbound webhooks in step 5.
Looking for the full endpoint-by-endpoint spec instead? Browse the OpenAPI reference (machine-readable spec at /api/openapi.json).
API keys are scoped and rotatable per tenant (ADR-010 §3.6). The raw key is shown once, at creation — myAI never stores or displays it again, so copy it into a secrets manager immediately.
live or test), and choose scopes — leave scopes empty for full access, or grant only what the integration needs (see the table below).myai_live_8Kf2… — the prefix is safe to log, the rest is not.Rotating a key (same page) keeps the old one valid for a 60-minute grace window by default, so you can swap credentials with zero downtime. Revoking is instant, no grace.
| Scope | Grants |
|---|---|
| * | Full access — every tool family below. |
| brain:read | Read brain namespaces, atoms, and search. |
| brain:write | Commit, stash, merge brain atoms. |
| tasks:read | List and read the cross-repo task queue. |
| tasks:write | Create, claim, update, and fail tasks. |
| memory:read | Search SONA memory / RAG context. |
| memory:write | Store new memory chunks. |
| chat | Route messages through a session. |
Send the key as a bearer token, or via the dedicated header — both are accepted identically on every REST and MCP route:
Authorization: Bearer myai_live_8Kf2...
# — or —
x-api-key: myai_live_8Kf2...A missing or invalid key on a route that requires one returns 401 UNAUTHORIZED — see the full error-code table in step 7.
The REST gateway is a plain JSON HTTP API. /health is unauthenticated — a good first call to confirm you can reach the endpoint at all:
curl http://localhost:3200/healthList your tenant's task queue:
curl http://localhost:3200/api/tasks \
-H "Authorization: Bearer $MYAI_API_KEY"Queue a new task:
curl -X POST http://localhost:3200/api/tasks \
-H "Authorization: Bearer $MYAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"repo": "my-app",
"title": "Sync inventory from Zapier",
"priority": "P2"
}'The same gateway also speaks MCP (JSON-RPC 2.0 over streamable HTTP) at a single POST /mcp endpoint — same auth header, same API key. Handshake first:
curl -X POST http://localhost:3100/mcp \
-H "Authorization: Bearer $MYAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}'Discover the available tools:
curl -X POST http://localhost:3100/mcp \
-H "Authorization: Bearer $MYAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/list"}'Call one — tasks_list mirrors the REST GET /api/tasks example above:
curl -X POST http://localhost:3100/mcp \
-H "Authorization: Bearer $MYAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": { "name": "tasks_list", "arguments": { "repo": "my-app" } }
}'Add an Idempotency-Key header on write tools (e.g. tasks_create) to safely retry a call without double-creating the resource.
Rather than polling, register an HTTPS endpoint and subscribe to lifecycle events — this is the trigger side of a Zapier or n8n connector. Each matching event delivers an HMAC-signed POST with at-least-once delivery.
curl -X POST http://localhost:3200/api/webhooks \
-H "Authorization: Bearer $MYAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://hooks.zapier.com/hooks/catch/xxxx/yyyy/",
"events": ["task.completed", "task.blocked"]
}'Valid event names: task.created, task.claimed, task.review, task.blocked, task.completed, plan.updated, runner.fired — or ["*"] for all of them. Verify deliveries with the X-Myai-Signature header (HMAC of the raw body using the secret returned once at creation); the event name and a delivery id ride along on X-Myai-Event / X-Myai-Delivery.
Two independent limits apply per tenant, both plan-scoped:
| Plan | Burst (per minute) | Monthly quota |
|---|---|---|
| Free | 60 req/min | 10,000 req/month |
| Solo | 300 req/min | 200,000 req/month |
| Team | 1,000 req/min | 2,000,000 req/month |
| Scale | Unlimited | Unlimited |
Exceeding either returns 429 with a Retry-After header (seconds to wait) and a JSON body carrying the code:
HTTP/1.1 429 Too Many Requests
Retry-After: 12
{ "error": "Too many requests", "code": "RATE_LIMITED", "retryAfter": 12 }HTTP/1.1 429 Too Many Requests
Retry-After: 1382400
{
"error": "monthly request quota exceeded — upgrade your plan or wait for the next billing period",
"code": "QUOTA_EXCEEDED",
"retryAfter": 1382400,
"limit": 10000,
"used": 10000
}Back off exponentially on RATE_LIMITED; on QUOTA_EXCEEDED either wait for the UTC month to roll over or upgrade the plan from Pricing.
Every rejected request returns a flat JSON body — { error, code } at minimum, never the offending key. code is the stable field to branch on; the message text may change.
| Code | HTTP | Meaning |
|---|---|---|
| UNAUTHORIZED | 401 | Missing, malformed, or invalid API key. |
| FORBIDDEN | 403 | Key is valid but the caller's role/capability doesn't permit this route (RBAC v1). |
| RATE_LIMITED | 429 | Burst rate limit hit (per-plan requests/min). Respect the `Retry-After` header (seconds). |
| QUOTA_EXCEEDED | 429 | Monthly plan request quota hit. `Retry-After` is seconds until the UTC month rolls over; `limit`/`used` are included in the body. |
| PLAN_LIMIT_EXCEEDED | 402 | A plan resource cap (e.g. connected repos) was exceeded — upgrade to proceed. |
| REGION_MISMATCH | 403 | Tenant is pinned to a data-residency region this gateway endpoint does not serve (ADR-023). Body includes the correct regional endpoint. |
| BAD_REQUEST | 400 | Request body/params failed validation. |
| NOT_FOUND | 404 | Resource does not exist (or is not visible to this tenant). |
| SESSION_REVOKED | 401 | The session/device behind this call was revoked — re-authenticate. |
| ADMIN_DISABLED | 503 | An admin-only route was called but no admin token is configured on this deployment. |
| INTERNAL_ERROR | 500 | Unexpected server error — safe to retry with backoff. |