ResilientLang docsDeveloper documentation (draft, product name is a placeholder)

API overview

Base path /v1. JSON over HTTPS. The machine-readable description is openapi.json; every endpoint is listed in the API reference, which is generated from it.

Authentication#

Send a secret API key as a bearer token:

Authorization: Bearer rl_sec_live_...

Keys are described in API keys. Keys are read only from the Authorization header; never put one in a URL. Each endpoint needs one scope, shown in the reference. The scope list is in API keys. A key restricted to one site can only touch that site. A resource that belongs to another tenant is reported as 404, the same as a resource that does not exist.

Some features have their own routes that are described on separate pages because they are not in openapi.json yet: webhooks, audit log, billing, licensing and team and members. Team routes use a sign-in session, not an API key.

Two routes are not authenticated with a secret key: GET /v1/health (liveness, no data) and POST /v1/discover (optional, called by the browser snippet with a site key from an allowed Origin, rate limited, off by default).

Errors#

Errors use RFC 9457 application/problem+json:

{ "type": "urn:resilientlang:problem:validation", "title": "Validation failed", "status": 400,
  "detail": "targetLanguages must not be empty",
  "errors": { "targetLanguages": ["must not be empty"] },
  "instance": "/v1/sites" }
StatusMeaning
400Validation failed or malformed request
401Missing or invalid API key
403Insufficient scope, origin not allowed, or the account is suspended
402A plan limit, the AI-word allowance or the licence blocks the action (see Errors)
404Not found (also for other tenants' resources)
409An identical request with the same Idempotency-Key is still running
413Body too large
415Unsupported media type
422Idempotency-Key reused with a different request, or an import was rejected
429Rate limited; read Retry-After
500Unexpected error; no details are exposed, quote the reference
503A plan, quota, licence or suspension check could not run; the API fails closed. Retry after Retry-After

type is a urn:resilientlang:problem:<code> value. The codes the control-plane API can return are listed in the error catalogue, generated from the OpenAPI file (x-problem-types). A 401 carries WWW-Authenticate: Bearer.

Pagination#

List endpoints take ?cursor=&limit= (maximum 100) and return { "items": [...], "nextCursor": "..." }. Pass nextCursor back as cursor; when it is absent you have reached the end.

Idempotency#

Write endpoints accept an Idempotency-Key header (up to 255 characters). Retrying the same request with the same key returns the stored response with Idempotent-Replayed: true and does not repeat the action. Reusing a key with a different request returns 422; reusing it while the first request is still running returns 409. Use a fresh key per logical operation.

Rate limits#

Limits apply per key and per IP, and are stricter on unauthenticated routes. Authenticated responses carry X-RateLimit-Limit and X-RateLimit-Remaining; a 429 carries Retry-After in seconds. The numeric limits are configuration, not a published promise.

Key rotation#

POST /v1/keys/{id}/rotate returns a new key at once (shown once). The old key keeps working for gracePeriodSeconds (default 24 hours, at most 30 days), so deploy the new key everywhere before the grace period ends, then the old one stops. Revoke with DELETE /v1/keys/{id}.

Quota#

GET /v1/usage/quota (scope usage:read) reports the plan allowance and where the tenant stands in the current period. See Errors for what happens when it is exhausted.

Asynchronous jobs#

scan, translate and publish return 202 with a job (or a list of jobs). Poll GET /v1/jobs/{jobId} until state is succeeded, failed or canceled. Job states: queued, running, succeeded, failed, canceled.

Data handling#

Machine-translation providers receive page text only, never keys, emails or tenant data. Bring-your-own provider keys are encrypted at rest. See Security model.