Error Envelope

Errors use one structured JSON shape across the runtime API.

Clients should not parse English text to infer behavior. Persistly returns a stable error envelope with a machine-readable code and optional structured details.

Response

HTTP 413 Payload Too Large

The same envelope shape is used for 400, 401, 404, 429, and 500 responses.

HTTP/1.1 413 Payload Too Large
Content-Type: application/json

{
  "error": {
    "code": "payload_too_large",
    "message": "State exceeds the maximum allowed size.",
    "details": {
      "field": "state",
      "maxBytes": 262144
    }
  }
}

Rate Limit

HTTP 429 includes retry guidance.

SDKs should surface this as a typed rate-limit error so games can pause sync attempts instead of hammering the runtime.

HTTP/1.1 429 Too Many Requests
Retry-After: 18
Content-Type: application/json

{
  "error": {
    "code": "rate_limited",
    "message": "Too many runtime requests for this environment.",
    "details": {
      "retryAfter": 18,
      "windowSeconds": 60
    }
  }
}

Handling Rules

Use the envelope to drive client behavior.

Read both HTTP status and error.code.

Treat 400 and 413 as caller/actionable problems.

Treat 401 as key/environment/auth configuration failure.

Treat 429 as retry-later behavior. Honor Retry-After before retrying.

Treat 500 as unknown-result behavior and retry intentionally.

Rate Limits

Plan limits protect the runtime without changing the save contract.

Per-minute limits come from the project's active plan entitlement.

The runtime uses a 60-second window for request-rate enforcement.

Do not retry every frame. Back off until Retry-After has elapsed.

Monthly request totals are plan boundaries today; hard monthly enforcement needs usage aggregation first.