FalconryScale
Developers

Errors and rate limits

The error response shape, status codes, and how often you can call the API.

Error format

Every error, on the REST API and the MCP server alike, is a JSON body with a short, machine-readable error code and a human-readable message:

{
  "error": "not_found",
  "message": "Not found, or not visible to this caller."
}

Check the error field in code, not the message text, which is meant for a person reading it and may change.

A validation failure (400) adds a fields object naming what was wrong with each input:

{
  "error": "invalid_input",
  "message": "Request failed validation.",
  "fields": {
    "weightGrams": "Expected number, received string"
  }
}

Status codes

StatuserrorWhen
400invalid_inputA parameter or body field failed validation, or the request body wasn't valid JSON.
401unauthorizedThe request has no credential, or the credential is invalid or expired.
403forbiddenThe credential is valid but can't be used here, for example it carries neither falconry:read nor falconry:write.
403insufficient_scopeThe credential is read-only and the request is a write operation.
404not_foundThe endpoint doesn't exist, or the resource does but isn't visible to this caller.
405method_not_allowedThe endpoint exists but not for this HTTP method.
409quota_exceededThe write conflicts with your account's current plan or quota.
413payload_too_largeThe request body is bigger than 64 KB.
429rate_limitedToo many requests. See rate limits below.
500internal_errorSomething went wrong on FalconryScale's side.
503auth_unavailableYour credential couldn't be checked right now, not that it's invalid. Carries a Retry-After header, in seconds. Wait that long and try again; your credential itself needs no action.

A write can also surface other invalid_* codes from backend validation (for example invalid_date_range or invalid_weight), always as a 400 with the same { error, message } shape.

Authentication challenges

A 401 or a scope-related 403 carries a WWW-Authenticate header pointing at this resource's OAuth metadata, so a compliant client can recover automatically:

WWW-Authenticate: Bearer error="invalid_token", resource_metadata="https://app.falconryscale.com/.well-known/oauth-protected-resource/mcp"

error="invalid_token" appears when a credential was sent and rejected; it's omitted when no credential was sent at all. error="insufficient_scope" appears instead when the credential is valid but lacks the scope the request needs.

A 503 auth_unavailable carries no WWW-Authenticate header at all, it isn't a verdict on your credential, just a sign the check itself couldn't run. Retry after the Retry-After header's delay instead of treating it like a 401.

Rate limits

Three limits apply, in order, on every request to the REST API and the MCP server alike:

  1. Per IP, before your credential is even checked: 120 requests per minute, burst 60. This guards against a flood of bad credentials from one source and applies to every request, authenticated or not.
  2. Per credential: 60 requests per minute, burst 30. This is your real budget, each API key or OAuth connection gets its own bucket.
  3. Per account, across every credential you have: 60 requests per minute, burst 30. Creating more API keys doesn't multiply your total budget, they all draw from this same ceiling once you're signed in.

On the MCP server, each tools/call is charged against your per-account limit too, on top of the HTTP-request charge above, since a tool call is what actually costs a database round trip.

Going over any of these returns 429 with a Retry-After header, in seconds:

HTTP/1.1 429 Too Many Requests
Retry-After: 12

{ "error": "rate_limited", "message": "Too many requests." }

Wait at least that long before retrying. If you're regularly hitting this, batch calls where you can, get_today_summary and get_latest_weights each cover what would otherwise take several separate requests.

Request size

A request body on the REST API or the MCP server is capped at 64 KB. A larger body is rejected with 413 payload_too_large before it's read, or as soon as it's read if your client doesn't send a Content-Length header.

Individual fields have their own, smaller limits, an id is at most 64 characters, notes are capped at 2000 characters, and a location description at 500, all well inside the overall body cap. A field over its limit comes back as the usual 400 invalid_input with a fields entry naming it.

get_weight_history defaults to, and caps at, 500 rows per call. list_health_records and list_medications each default to, and cap at, 200 rows per call. Pass limit to ask for fewer.

MCP batch requests

The MCP server doesn't accept JSON-RPC batch requests (a JSON array of calls in one HTTP request). A batch body is rejected outright with a JSON-RPC error, before any of it runs:

{ "jsonrpc": "2.0", "id": null, "error": { "code": -32600, "message": "Invalid Request: JSON-RPC batch requests are not supported." } }

Send one call per request instead.

On this page