Skip to page content
Docs
Make Agent Fast documentation

Scopes and errors

Grant least privilege and handle every stable public API error code.

At a glance

Grant least privilege and handle every stable public API error code.

API request pathScoped key → versioned resource → signed response
App / SDKBearer keymaf_live_…/api/v1/…ResourceJSON
23 scopesStable codesRequest IDs

Every public API operation requires one explicit scope. A valid credential without that scope receives 403 insufficient_scope; it is never silently upgraded to broader access.

Scope reference#

ScopeAllows
account:readRead the authenticated account, plan, entitlements, and wallet summary
sites:readList and retrieve sites
sites:writeCreate, update, publish, and unpublish sites
agents:readRead agent settings
agents:writeUpdate persona, instructions, languages, voice, embed state, and allowed origins
knowledge:readList knowledge sources and FAQs
knowledge:writeIngest or delete text sources and create, update, or delete FAQs
conversations:readList conversations and retrieve their messages
leads:readList captured leads
analytics:readRead site analytics events
connectors:readList connector state without returning secrets
connectors:writeCreate, update, enable, disable, and remove connectors
domains:readRead domain state and required DNS records
domains:writeConnect, verify, update, and remove domains
broadcasts:readList broadcasts and delivery state
broadcasts:writeCreate drafts and queue a broadcast send
notifications:readList owner notifications
notifications:writeMark notifications read or unread
monetization:readList monetization products
monetization:writeCreate, update, activate, deactivate, and delete products
usage:readRead metered usage events
webhooks:readList webhook endpoints and delivery state
webhooks:writeCreate and delete webhook endpoints

Use read scopes for reporting jobs. Add a write scope only when the integration performs that mutation. For example, a lead export normally needs sites:read and leads:read, not sites:write or agents:write.

Scope failures#

{
  "error": {
    "code": "insufficient_scope",
    "message": "The API key does not grant the required scope.",
    "details": { "required": ["sites:write"] },
    "request_id": "6c0b2f2e-..."
  }
}

Create a replacement key with the missing scope and update the server secret. Existing API-key scopes cannot be expanded in place; this makes privilege changes explicit and auditable.

Error envelope#

All API errors use the same top-level shape:

type ApiError = {
  error: {
    code: string;
    message: string;
    details?: unknown;
    request_id: string;
  };
};

Branch on error.code, not the English message. Messages can improve without a version change. Log error.request_id and the x-request-id response header with the operation name, status, and retry attempt—but never log the authorization header or request secrets.

Status and code reference#

HTTPStable codeMeaningNormal response
400invalid_requestValidation failed or a field is unsupportedCorrect the fields in details; do not retry unchanged input
400invalid_jsonBody is not a JSON object or contains invalid JSONSerialize one valid JSON object
401authentication_requiredBearer header is missingAttach a server-side credential
401invalid_api_keyKey is invalid, expired, revoked, or its owner no longer existsReplace or rotate the key
403subscription_requiredThe owner does not have an active paid planRestore the subscription before retrying
403insufficient_scopeThe credential lacks the operation's scopeCreate a least-privilege replacement credential
403account_pausedAPI access is paused for the accountResume API access or contact the account owner
404not_foundEndpoint or owned resource was not foundVerify the path and tenant-owned ID
409conflictCurrent resource state prevents the actionRead current state before retrying
415invalid_requestMutation body is not application/jsonSend Content-Type: application/json
429rate_limit_exceededThe key's one-minute plan bucket is exhaustedWait for Retry-After and apply jitter
500internal_errorThe request could not be completedRetry a safe or idempotent operation and report the request ID

Resources outside the credential owner's account can return 404 instead of revealing whether another tenant's ID exists.

Validation details#

Field validation returns paths that can be shown next to your own form controls:

{
  "error": {
    "code": "invalid_request",
    "message": "Request validation failed.",
    "details": [
      { "path": "content.headline", "message": "String must contain at least 1 character(s)" }
    ],
    "request_id": "6c0b2f2e-..."
  }
}

Mutation bodies must be JSON objects. Arrays, empty bodies, form data, and JSON sent with a text content type are rejected.

Retry decisions#

  • Retry 429 after the number of seconds in Retry-After.
  • Retry 500 only for safe reads or writes protected by the same Idempotency-Key.
  • Retry the in-progress idempotency 409 after its Retry-After: 2 header.
  • Do not retry 400, 401, 403, 404, or a state conflict until the cause changes.

See Rate limits for backoff behavior and API reference for the required scope on each operation.