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

API reference

Generated from openapi.json (ResilientLang control-plane API 1.0.0), 24 operations. Concepts (authentication, errors, pagination, idempotency) are on the overview page.

System#

Liveness and this document. No key needed.

GET /v1/health#

Liveness (no data)

Authentication: None (public)

Success response (200)

FieldTypeRequiredDescription
statusstringyes

Status codes

CodeMeaning
200Success
429Rate limited (see Retry-After)
500Unexpected error (no details are exposed; quote the reference)

Example

curl -sS -X GET "$RL_API_BASE/v1/health"

GET /v1/openapi.json#

This document

Authentication: None (public)

Success response (200)

Status codes

CodeMeaning
200Success
429Rate limited (see Retry-After)
500Unexpected error (no details are exposed; quote the reference)

Example

curl -sS -X GET "$RL_API_BASE/v1/openapi.json"

Sites#

Create and configure sites (name, languages, allowed origins).

GET /v1/sites#

List sites

Authentication: Secret API key · Required scope: sites:read

Parameters

NameInTypeRequiredDescription
cursorquerystringno
limitqueryintegerno

Success response (200)

FieldTypeRequiredDescription
itemsarray of objectyes
items[].idstring (uuid)yes
items[].siteKeystringyes
items[].namestringyes
items[].sourceLanguagestringyes
items[].targetLanguagesarray of stringyes
items[].allowedOriginsarray of stringyes
nextCursorstringno

Status codes

CodeMeaning
200Success
400Validation failed or malformed request
401Missing or invalid API key
403Insufficient scope, or origin not allowed
429Rate limited (see Retry-After)
500Unexpected error (no details are exposed; quote the reference)

Example

curl -sS -X GET "$RL_API_BASE/v1/sites" \
  -H "Authorization: Bearer $RL_SECRET_KEY"

POST /v1/sites#

Create a site

Authentication: Secret API key · Required scope: sites:write

Parameters

NameInTypeRequiredDescription
Idempotency-Keyheaderstringno

Request body

FieldTypeRequiredDescription
namestringyes
sourceLanguagestringyes
targetLanguagesarray of stringyes
allowedOriginsarray of stringno

Success response (201)

FieldTypeRequiredDescription
idstring (uuid)yes
siteKeystringyes
namestringyes
sourceLanguagestringyes
targetLanguagesarray of stringyes
allowedOriginsarray of stringyes

Response example

{
  "id": "3f2b1c9e-6a4d-4c8e-9a53-0d2f7b1e8c11",
  "siteKey": "rl_site_live_abcdefghijklmnopqrstuv",
  "name": "My shop",
  "sourceLanguage": "en",
  "targetLanguages": [
    "fr",
    "de"
  ],
  "allowedOrigins": [
    "https://shop.example.com"
  ]
}

Status codes

CodeMeaning
201Success
400Validation failed or malformed request
401Missing or invalid API key
402A plan, allowance or licence blocks this action (see the problem type; D41). Retry-After is set when the allowance resets.
403Insufficient scope, or origin not allowed
409Idempotent request still in progress
413Body too large
415Unsupported media type
422Idempotency-Key reused with a different request, or the import was rejected
429Rate limited (see Retry-After)
500Unexpected error (no details are exposed; quote the reference)
503A plan/quota/licence/suspension check was unavailable (fails closed); retry after Retry-After.

Example

curl -sS -X POST "$RL_API_BASE/v1/sites" \
  -H "Authorization: Bearer $RL_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"string","sourceLanguage":"string","targetLanguages":["string"],"allowedOrigins":["string"]}'

GET /v1/sites/{siteId}#

Get a site

Authentication: Secret API key · Required scope: sites:read

Parameters

NameInTypeRequiredDescription
siteIdpathstringyes

Success response (200)

FieldTypeRequiredDescription
idstring (uuid)yes
siteKeystringyes
namestringyes
sourceLanguagestringyes
targetLanguagesarray of stringyes
allowedOriginsarray of stringyes

Response example

{
  "id": "3f2b1c9e-6a4d-4c8e-9a53-0d2f7b1e8c11",
  "siteKey": "rl_site_live_abcdefghijklmnopqrstuv",
  "name": "My shop",
  "sourceLanguage": "en",
  "targetLanguages": [
    "fr",
    "de"
  ],
  "allowedOrigins": [
    "https://shop.example.com"
  ]
}

Status codes

CodeMeaning
200Success
400Validation failed or malformed request
401Missing or invalid API key
403Insufficient scope, or origin not allowed
404Not found (also returned for other tenants' resources)
429Rate limited (see Retry-After)
500Unexpected error (no details are exposed; quote the reference)

Example

curl -sS -X GET "$RL_API_BASE/v1/sites/${SITE_ID}" \
  -H "Authorization: Bearer $RL_SECRET_KEY"

PATCH /v1/sites/{siteId}#

Update site settings

Authentication: Secret API key · Required scope: sites:write

Parameters

NameInTypeRequiredDescription
siteIdpathstringyes
Idempotency-Keyheaderstringno

Request body

FieldTypeRequiredDescription
namestringno
targetLanguagesarray of stringno
allowedOriginsarray of stringno

Success response (200)

FieldTypeRequiredDescription
idstring (uuid)yes
siteKeystringyes
namestringyes
sourceLanguagestringyes
targetLanguagesarray of stringyes
allowedOriginsarray of stringyes

Response example

{
  "id": "3f2b1c9e-6a4d-4c8e-9a53-0d2f7b1e8c11",
  "siteKey": "rl_site_live_abcdefghijklmnopqrstuv",
  "name": "My shop",
  "sourceLanguage": "en",
  "targetLanguages": [
    "fr",
    "de"
  ],
  "allowedOrigins": [
    "https://shop.example.com"
  ]
}

Status codes

CodeMeaning
200Success
400Validation failed or malformed request
401Missing or invalid API key
402A plan, allowance or licence blocks this action (see the problem type; D41). Retry-After is set when the allowance resets.
403Insufficient scope, or origin not allowed
404Not found (also returned for other tenants' resources)
409Idempotent request still in progress
413Body too large
415Unsupported media type
422Idempotency-Key reused with a different request, or the import was rejected
429Rate limited (see Retry-After)
500Unexpected error (no details are exposed; quote the reference)
503A plan/quota/licence/suspension check was unavailable (fails closed); retry after Retry-After.

Example

curl -sS -X PATCH "$RL_API_BASE/v1/sites/${SITE_ID}" \
  -H "Authorization: Bearer $RL_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"string","targetLanguages":["string"],"allowedOrigins":["string"]}'

Strings#

Submit extracted source strings; keys are computed by the server (BUNDLE_FORMAT.md).

POST /v1/sites/{siteId}/strings#

Submit extracted strings (max 1000)

Up to 1000 items. The response lists the key of every item in order; identical text (after normalisation) yields the same key and is stored once.

Authentication: Secret API key · Required scope: strings:write

Parameters

NameInTypeRequiredDescription
siteIdpathstringyes
Idempotency-Keyheaderstringno

Request body

FieldTypeRequiredDescription
itemsarray of objectyes
items[].textstringyes
items[].kindenum: text | attrno
items[].contextstringno
items[].urlstring (uri)no

Success response (200)

FieldTypeRequiredDescription
itemsarray of objectyes
items[].keystringyes
items[].kindstringyes
storedintegerno

Response example

{
  "items": [
    {
      "key": "0123456789abcdef",
      "kind": "text"
    },
    {
      "key": "fedcba9876543210",
      "kind": "attr"
    }
  ],
  "stored": 2
}

Status codes

CodeMeaning
200Success
400Validation failed or malformed request
401Missing or invalid API key
402A plan, allowance or licence blocks this action (see the problem type; D41). Retry-After is set when the allowance resets.
403Insufficient scope, or origin not allowed
404Not found (also returned for other tenants' resources)
409Idempotent request still in progress
413Body too large
415Unsupported media type
422Idempotency-Key reused with a different request, or the import was rejected
429Rate limited (see Retry-After)
500Unexpected error (no details are exposed; quote the reference)
503A plan/quota/licence/suspension check was unavailable (fails closed); retry after Retry-After.

Example

curl -sS -X POST "$RL_API_BASE/v1/sites/${SITE_ID}/strings" \
  -H "Authorization: Bearer $RL_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{"items":[{"text":"string"}]}'

Jobs#

Asynchronous work (scan, translate, publish) and its status.

POST /v1/sites/{siteId}/scan#

Start a crawl (async job)

Every URL and the sitemap URL must be on one of the site's allowedOrigins and pass the SSRF check. Returns a job.

Authentication: Secret API key · Required scope: sites:write

Parameters

NameInTypeRequiredDescription
siteIdpathstringyes
Idempotency-Keyheaderstringno

Request body

FieldTypeRequiredDescription
urlsarray of stringno
sitemapUrlstringno
respectRobotsbooleanno

Success response (202)

FieldTypeRequiredDescription
idstring (uuid)yes
kindenum: scan | translate | publishyes
siteIdstring (uuid)yes
stateenum: queued | running | succeeded | failed | canceledyes
attemptsintegeryes
progressPercentintegeryes
createdAtstring (date-time)yes
finishedAtstring (date-time)no
errorstringno
resultobjectnoPresent on succeeded publish jobs.
result.versionintegeryes
result.publishedAtstring (date-time)no
result.targetsarray of objectno
result.targets[].targetstringyes
result.targets[].okbooleanyes
result.targets[].errorstringno

Response example

{
  "id": "9b1e6c52-2f43-4a8e-8d0b-5c7a1f3e9a20",
  "kind": "publish",
  "siteId": "3f2b1c9e-6a4d-4c8e-9a53-0d2f7b1e8c11",
  "state": "succeeded",
  "attempts": 1,
  "progressPercent": 100,
  "createdAt": "2026-10-28T12:00:00Z",
  "finishedAt": "2026-10-28T12:00:09Z",
  "result": {
    "version": 7,
    "publishedAt": "2026-10-28T12:00:09Z",
    "targets": [
      {
        "target": "r2-primary",
        "ok": true
      },
      {
        "target": "cdn-secondary",
        "ok": true
      }
    ]
  }
}

Status codes

CodeMeaning
202Success
400Validation failed or malformed request
401Missing or invalid API key
403Insufficient scope, or origin not allowed
404Not found (also returned for other tenants' resources)
409Idempotent request still in progress
413Body too large
415Unsupported media type
422Idempotency-Key reused with a different request, or the import was rejected
429Rate limited (see Retry-After)
500Unexpected error (no details are exposed; quote the reference)

Example

curl -sS -X POST "$RL_API_BASE/v1/sites/${SITE_ID}/scan" \
  -H "Authorization: Bearer $RL_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{"urls":["string"],"sitemapUrl":"string","respectRobots":true}'

POST /v1/sites/{siteId}/translate#

Machine-translate missing strings (async job)

Enqueues one job per target language (or per requested language). Never overwrites reviewed or manual translations.

Authentication: Secret API key · Required scope: translations:write

Parameters

NameInTypeRequiredDescription
siteIdpathstringyes
Idempotency-Keyheaderstringno

Request body

FieldTypeRequiredDescription
langsarray of stringno
keysarray of stringno
forcebooleanno

Success response (202)

FieldTypeRequiredDescription
jobsarray of objectyes
jobs[].idstring (uuid)yes
jobs[].kindenum: scan | translate | publishyes
jobs[].siteIdstring (uuid)yes
jobs[].stateenum: queued | running | succeeded | failed | canceledyes
jobs[].attemptsintegeryes
jobs[].progressPercentintegeryes
jobs[].createdAtstring (date-time)yes
jobs[].finishedAtstring (date-time)no
jobs[].errorstringno
jobs[].resultobjectnoPresent on succeeded publish jobs.
jobs[].result.versionintegeryes
jobs[].result.publishedAtstring (date-time)no
jobs[].result.targetsarray of objectno
jobs[].result.targets[].targetstringyes
jobs[].result.targets[].okbooleanyes
jobs[].result.targets[].errorstringno

Status codes

CodeMeaning
202Success
400Validation failed or malformed request
401Missing or invalid API key
402A plan, allowance or licence blocks this action (see the problem type; D41). Retry-After is set when the allowance resets.
403Insufficient scope, or origin not allowed
404Not found (also returned for other tenants' resources)
409Idempotent request still in progress
413Body too large
415Unsupported media type
422Idempotency-Key reused with a different request, or the import was rejected
429Rate limited (see Retry-After)
500Unexpected error (no details are exposed; quote the reference)
503A plan/quota/licence/suspension check was unavailable (fails closed); retry after Retry-After.

Example

curl -sS -X POST "$RL_API_BASE/v1/sites/${SITE_ID}/translate" \
  -H "Authorization: Bearer $RL_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{"langs":["string"],"keys":["string"],"force":true}'

POST /v1/sites/{siteId}/publish#

Build and publish bundles (async job)

Builds and publishes signed bundles to every storage target. Poll the job; a succeeded job's `result.version` is the published version.

Authentication: Secret API key · Required scope: bundles:publish

Parameters

NameInTypeRequiredDescription
siteIdpathstringyes
Idempotency-Keyheaderstringno

Request body

FieldTypeRequiredDescription
onlyIfChangedbooleanno

Success response (202)

FieldTypeRequiredDescription
idstring (uuid)yes
kindenum: scan | translate | publishyes
siteIdstring (uuid)yes
stateenum: queued | running | succeeded | failed | canceledyes
attemptsintegeryes
progressPercentintegeryes
createdAtstring (date-time)yes
finishedAtstring (date-time)no
errorstringno
resultobjectnoPresent on succeeded publish jobs.
result.versionintegeryes
result.publishedAtstring (date-time)no
result.targetsarray of objectno
result.targets[].targetstringyes
result.targets[].okbooleanyes
result.targets[].errorstringno

Response example

{
  "id": "9b1e6c52-2f43-4a8e-8d0b-5c7a1f3e9a20",
  "kind": "publish",
  "siteId": "3f2b1c9e-6a4d-4c8e-9a53-0d2f7b1e8c11",
  "state": "succeeded",
  "attempts": 1,
  "progressPercent": 100,
  "createdAt": "2026-10-28T12:00:00Z",
  "finishedAt": "2026-10-28T12:00:09Z",
  "result": {
    "version": 7,
    "publishedAt": "2026-10-28T12:00:09Z",
    "targets": [
      {
        "target": "r2-primary",
        "ok": true
      },
      {
        "target": "cdn-secondary",
        "ok": true
      }
    ]
  }
}

Status codes

CodeMeaning
202Success
400Validation failed or malformed request
401Missing or invalid API key
402A plan, allowance or licence blocks this action (see the problem type; D41). Retry-After is set when the allowance resets.
403Insufficient scope, or origin not allowed
404Not found (also returned for other tenants' resources)
409Idempotent request still in progress
413Body too large
415Unsupported media type
422Idempotency-Key reused with a different request, or the import was rejected
429Rate limited (see Retry-After)
500Unexpected error (no details are exposed; quote the reference)
503A plan/quota/licence/suspension check was unavailable (fails closed); retry after Retry-After.

Example

curl -sS -X POST "$RL_API_BASE/v1/sites/${SITE_ID}/publish" \
  -H "Authorization: Bearer $RL_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{"onlyIfChanged":true}'

GET /v1/jobs/{jobId}#

Job status

Status of a job created by scan, translate or publish. Succeeded publish jobs include result.version, publishedAt and per-target results.

Authentication: Secret API key

Parameters

NameInTypeRequiredDescription
jobIdpathstringyes

Success response (200)

FieldTypeRequiredDescription
idstring (uuid)yes
kindenum: scan | translate | publishyes
siteIdstring (uuid)yes
stateenum: queued | running | succeeded | failed | canceledyes
attemptsintegeryes
progressPercentintegeryes
createdAtstring (date-time)yes
finishedAtstring (date-time)no
errorstringno
resultobjectnoPresent on succeeded publish jobs.
result.versionintegeryes
result.publishedAtstring (date-time)no
result.targetsarray of objectno
result.targets[].targetstringyes
result.targets[].okbooleanyes
result.targets[].errorstringno

Response example

{
  "id": "9b1e6c52-2f43-4a8e-8d0b-5c7a1f3e9a20",
  "kind": "publish",
  "siteId": "3f2b1c9e-6a4d-4c8e-9a53-0d2f7b1e8c11",
  "state": "succeeded",
  "attempts": 1,
  "progressPercent": 100,
  "createdAt": "2026-10-28T12:00:00Z",
  "finishedAt": "2026-10-28T12:00:09Z",
  "result": {
    "version": 7,
    "publishedAt": "2026-10-28T12:00:09Z",
    "targets": [
      {
        "target": "r2-primary",
        "ok": true
      },
      {
        "target": "cdn-secondary",
        "ok": true
      }
    ]
  }
}

Status codes

CodeMeaning
200Success
401Missing or invalid API key
404Not found (also returned for other tenants' resources)
429Rate limited (see Retry-After)
500Unexpected error (no details are exposed; quote the reference)

Example

curl -sS -X GET "$RL_API_BASE/v1/jobs/${JOB_ID}" \
  -H "Authorization: Bearer $RL_SECRET_KEY"

Translations#

List translations and set manual overrides, which machine runs never overwrite.

GET /v1/sites/{siteId}/translations#

List translations

Authentication: Secret API key · Required scope: translations:read

Parameters

NameInTypeRequiredDescription
siteIdpathstringyes
cursorquerystringno
limitqueryintegerno
langquerystringyes
statusquerystringno

Success response (200)

FieldTypeRequiredDescription
itemsarray of objectyes
items[].keystringyes
items[].langstringyes
items[].textstringyes
items[].statusenum: machine | reviewed | manualyes
items[].updatedAtstring (date-time)yes
items[].flagsarray of stringno
nextCursorstringno

Status codes

CodeMeaning
200Success
400Validation failed or malformed request
401Missing or invalid API key
403Insufficient scope, or origin not allowed
404Not found (also returned for other tenants' resources)
429Rate limited (see Retry-After)
500Unexpected error (no details are exposed; quote the reference)

Example

curl -sS -X GET "$RL_API_BASE/v1/sites/${SITE_ID}/translations" \
  -H "Authorization: Bearer $RL_SECRET_KEY"

PUT /v1/sites/{siteId}/translations/{lang}/{key}#

Manual override

Authentication: Secret API key · Required scope: translations:write

Parameters

NameInTypeRequiredDescription
siteIdpathstringyes
langpathstringyes
keypathstringyes
Idempotency-Keyheaderstringno

Request body

FieldTypeRequiredDescription
textstringyes

Success response (200)

FieldTypeRequiredDescription
keystringyes
langstringyes
textstringyes
statusenum: machine | reviewed | manualyes
updatedAtstring (date-time)yes
flagsarray of stringno

Status codes

CodeMeaning
200Success
400Validation failed or malformed request
401Missing or invalid API key
403Insufficient scope, or origin not allowed
404Not found (also returned for other tenants' resources)
409Idempotent request still in progress
413Body too large
415Unsupported media type
422Idempotency-Key reused with a different request, or the import was rejected
429Rate limited (see Retry-After)
500Unexpected error (no details are exposed; quote the reference)

Example

curl -sS -X PUT "$RL_API_BASE/v1/sites/${SITE_ID}/translations/${LANG}/${KEY}" \
  -H "Authorization: Bearer $RL_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{"text":"string"}'

Glossary#

Do-not-translate terms and preferred translations.

GET /v1/sites/{siteId}/glossary#

Get glossary

Authentication: Secret API key · Required scope: translations:read

Parameters

NameInTypeRequiredDescription
siteIdpathstringyes

Success response (200)

FieldTypeRequiredDescription
doNotTranslatearray of stringno
preferredarray of objectno
preferred[].sourcestringyes
preferred[].langstringnoOmit to apply to every target language.
preferred[].targetstringyes

Response example

{
  "doNotTranslate": [
    "Acme"
  ],
  "preferred": [
    {
      "source": "cart",
      "lang": "fr",
      "target": "panier"
    }
  ]
}

Status codes

CodeMeaning
200Success
400Validation failed or malformed request
401Missing or invalid API key
403Insufficient scope, or origin not allowed
404Not found (also returned for other tenants' resources)
429Rate limited (see Retry-After)
500Unexpected error (no details are exposed; quote the reference)

Example

curl -sS -X GET "$RL_API_BASE/v1/sites/${SITE_ID}/glossary" \
  -H "Authorization: Bearer $RL_SECRET_KEY"

PUT /v1/sites/{siteId}/glossary#

Replace glossary

Authentication: Secret API key · Required scope: translations:write

Parameters

NameInTypeRequiredDescription
siteIdpathstringyes
Idempotency-Keyheaderstringno

Request body

FieldTypeRequiredDescription
doNotTranslatearray of stringno
preferredarray of objectno
preferred[].sourcestringyes
preferred[].langstringnoOmit to apply to every target language.
preferred[].targetstringyes

Success response (200)

FieldTypeRequiredDescription
doNotTranslatearray of stringno
preferredarray of objectno
preferred[].sourcestringyes
preferred[].langstringnoOmit to apply to every target language.
preferred[].targetstringyes

Response example

{
  "doNotTranslate": [
    "Acme"
  ],
  "preferred": [
    {
      "source": "cart",
      "lang": "fr",
      "target": "panier"
    }
  ]
}

Status codes

CodeMeaning
200Success
400Validation failed or malformed request
401Missing or invalid API key
403Insufficient scope, or origin not allowed
404Not found (also returned for other tenants' resources)
409Idempotent request still in progress
413Body too large
415Unsupported media type
422Idempotency-Key reused with a different request, or the import was rejected
429Rate limited (see Retry-After)
500Unexpected error (no details are exposed; quote the reference)

Example

curl -sS -X PUT "$RL_API_BASE/v1/sites/${SITE_ID}/glossary" \
  -H "Authorization: Bearer $RL_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{"doNotTranslate":["string"],"preferred":[{"source":"string","target":"string"}]}'

Interchange#

Export and import translations as JSON, XLIFF, PO/POT, CSV or TMX (the ownership guarantee).

GET /v1/sites/{siteId}/export#

Full export (format=json|xliff|xliff2|po|pot|csv|tmx, optional lang)

Returns every translation of the site in the chosen format so a customer can keep or edit them elsewhere. Never cached. Formats that hold one language per file (po, xliff2) return a .zip when several languages are included.

Authentication: Secret API key · Required scope: translations:read

Parameters

NameInTypeRequiredDescription
siteIdpathstringyes
formatqueryenum: json | xliff | xliff2 | po | pot | csv | tmxnoOutput format. xliff = XLIFF 1.2, xliff2 = XLIFF 2.x, pot = blank gettext template. Formats that hold one language (po, xliff2) return a .zip when several languages are exported.
langquerystringnoLimit to these target languages; repeat the parameter or separate with commas. Default: all.

Status codes

CodeMeaning
200The export file (a .zip when several one-language files are produced). Always Cache-Control: no-store.
400Validation failed or malformed request
401Missing or invalid API key
403Insufficient scope, or origin not allowed
404Not found (also returned for other tenants' resources)
429Rate limited (see Retry-After)
500Unexpected error (no details are exposed; quote the reference)

Example

curl -sS -X GET "$RL_API_BASE/v1/sites/${SITE_ID}/export" \
  -H "Authorization: Bearer $RL_SECRET_KEY"

POST /v1/sites/{siteId}/import#

Import translations from a file (multipart) or the JSON export (application/json)

Send multipart/form-data with field `file` (and `reference` for key-based formats such as android, messages-json and keyvalue-json), plus optional fields `format` (auto-detected when omitted), `lang` (for single-language files that do not state one), `status` (machine|reviewed|manual: overrides every entry's status; default: the file's own status, else manual) and `dryRun` (true = report the plan, write nothing). Strings the site does not know are skipped and listed in `issues`. Entries whose inline tags or placeholders do not survive are rejected. Any error-level issue rejects the whole import (422).

Authentication: Secret API key · Required scope: translations:write

Parameters

NameInTypeRequiredDescription
siteIdpathstringyes
Idempotency-Keyheaderstringno

Request body

FieldTypeRequiredDescription
filestring (binary)yesThe translation file.
referencestring (binary)noSource-language file; required for android, messages-json and keyvalue-json.
formatenum: json | xliff | xliff2 | po | csv | tmx | android | messages-json | keyvalue-jsonnoOmit to detect from the file name and content.
langstringnoTarget language for single-language files that do not state one.
statusenum: machine | reviewed | manualnoOverrides the status of every entry. Default: the file's own status, else manual.
dryRunbooleannoReport what would happen and write nothing.

Success response (200)

FieldTypeRequiredDescription
formatIdstringyes
dryRunbooleanyes
appliedbooleanyes
plannedintegeryes
writtenintegeryes
skippedProtectedintegernoMachine entries not written because a reviewed or manual translation exists.
statsobjectyes
stats.unitsReadintegerno
stats.matchedintegerno
stats.skippedUntranslatedintegerno
stats.skippedUnknownintegerno
stats.skippedInvalidintegerno
stats.conflictsintegerno
issuesarray of objectyes
issues[].severityenum: info | warning | erroryes
issues[].codestringyes
issues[].messagestringyes
issues[].wherestringno

Response example

{
  "formatId": "xliff",
  "dryRun": false,
  "applied": true,
  "planned": 1,
  "written": 1,
  "skippedProtected": 0,
  "stats": {
    "unitsRead": 2,
    "matched": 1,
    "skippedUntranslated": 0,
    "skippedUnknown": 1,
    "skippedInvalid": 0,
    "conflicts": 0
  },
  "issues": [
    {
      "severity": "warning",
      "code": "unknown-string",
      "message": "String not found on this site; skipped.",
      "where": "trans-unit b"
    }
  ]
}

Status codes

CodeMeaning
200Success
400Validation failed or malformed request
401Missing or invalid API key
403Insufficient scope, or origin not allowed
404Not found (also returned for other tenants' resources)
409Idempotent request still in progress
413Body too large
415Unsupported media type
422Idempotency-Key reused with a different request, or the import was rejected
429Rate limited (see Retry-After)
500Unexpected error (no details are exposed; quote the reference)

Example

curl -sS -X POST "$RL_API_BASE/v1/sites/${SITE_ID}/import" \
  -H "Authorization: Bearer $RL_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{"file":"string","reference":"string","format":"json","lang":"string","status":"machine","dryRun":true}'

Usage#

Strings, characters, engine cost and the plan allowance.

GET /v1/sites/{siteId}/usage#

Strings, characters, engine cost

Authentication: Secret API key · Required scope: usage:read

Parameters

NameInTypeRequiredDescription
siteIdpathstringyes
fromquerystringno
toquerystringno

Success response (200)

FieldTypeRequiredDescription
siteIdstring (uuid)yes
fromstring (date)yes
tostring (date)yes
stringsintegeryes
charactersintegeryes
engineCostUsdnumberyes

Status codes

CodeMeaning
200Success
400Validation failed or malformed request
401Missing or invalid API key
403Insufficient scope, or origin not allowed
404Not found (also returned for other tenants' resources)
429Rate limited (see Retry-After)
500Unexpected error (no details are exposed; quote the reference)

Example

curl -sS -X GET "$RL_API_BASE/v1/sites/${SITE_ID}/usage" \
  -H "Authorization: Bearer $RL_SECRET_KEY"

GET /v1/usage/quota#

Plan allowance and period usage for the key's tenant

The plan allowance and where the tenant stands in the current period (404 when quotas are not enabled on the deployment).

Authentication: Secret API key · Required scope: usage:read

Success response (200)

FieldTypeRequiredDescription
planIdstringyes
periodStartstring (date)yes
periodEndstring (date)yes
unlimitedbooleanyes
usedCharactersintegeryes
reservedCharactersintegerno
allowanceCharactersintegerno
usedWordsintegerno
allowanceWordsintegerno
remainingWordsintegerno
fractionnumberno
stateenum: ok | soft | exhaustedyes
byoCharactersintegerno
stringsDiscoveredintegerno
engineCostUsdnumberno

Status codes

CodeMeaning
200Success
401Missing or invalid API key
403Insufficient scope, or origin not allowed
404Not found (also returned for other tenants' resources)
429Rate limited (see Retry-After)
500Unexpected error (no details are exposed; quote the reference)
503A plan/quota/licence/suspension check was unavailable (fails closed); retry after Retry-After.

Example

curl -sS -X GET "$RL_API_BASE/v1/usage/quota" \
  -H "Authorization: Bearer $RL_SECRET_KEY"

Keys#

Secret API keys: create, rotate, revoke. Secrets are shown once.

GET /v1/keys#

List secret keys (never returns secrets)

Authentication: Secret API key · Required scope: keys:manage

Parameters

NameInTypeRequiredDescription
cursorquerystringno
limitqueryintegerno

Success response (200)

FieldTypeRequiredDescription
itemsarray of objectyes
items[].idstring (uuid)yes
items[].namestringyes
items[].prefixstringyes
items[].kindstringno
items[].scopesarray of stringyes
items[].siteIdstring (uuid)no
items[].expiresAtstring (date-time)no
items[].lastUsedAtstring (date-time)no
items[].revokedAtstring (date-time)no
items[].graceUntilstring (date-time)no
nextCursorstringno

Status codes

CodeMeaning
200Success
400Validation failed or malformed request
401Missing or invalid API key
403Insufficient scope, or origin not allowed
429Rate limited (see Retry-After)
500Unexpected error (no details are exposed; quote the reference)

Example

curl -sS -X GET "$RL_API_BASE/v1/keys" \
  -H "Authorization: Bearer $RL_SECRET_KEY"

POST /v1/keys#

Create a secret key (secret shown once)

The secret is returned once in this response and never again. The new key cannot hold scopes the calling key lacks. Test keys cannot create keys. Responses are never replayed from an Idempotency-Key.

Authentication: Secret API key · Required scope: keys:manage

Parameters

NameInTypeRequiredDescription
Idempotency-Keyheaderstringno

Request body

FieldTypeRequiredDescription
namestringyes
scopesarray of enum: sites:read | sites:write | strings:write | translations:read | translations:write | bundles:publish | usage:read | keys:manage | webhooks:manage | audit:read | audit:manage | billing:read | billing:manageyes
siteIdstring (uuid)no
expiresAtstring (date-time)no

Success response (201)

FieldTypeRequiredDescription
idstring (uuid)yes
namestringyes
prefixstringyes
kindstringno
scopesarray of stringyes
siteIdstring (uuid)no
expiresAtstring (date-time)no
lastUsedAtstring (date-time)no
revokedAtstring (date-time)no
graceUntilstring (date-time)no
secretstringnoShown once, never again.

Response example

{
  "id": "c2a4f0de-7b61-4e3a-9f55-1a8b2c3d4e5f",
  "name": "CI",
  "prefix": "rl_sec_live_",
  "kind": "secret",
  "scopes": [
    "strings:write",
    "bundles:publish"
  ],
  "secret": "rl_sec_live_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
}

Status codes

CodeMeaning
201Success
400Validation failed or malformed request
401Missing or invalid API key
403Insufficient scope, or origin not allowed
409Idempotent request still in progress
413Body too large
415Unsupported media type
422Idempotency-Key reused with a different request, or the import was rejected
429Rate limited (see Retry-After)
500Unexpected error (no details are exposed; quote the reference)

Example

curl -sS -X POST "$RL_API_BASE/v1/keys" \
  -H "Authorization: Bearer $RL_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"string","scopes":["sites:read"],"siteId":"00000000-0000-0000-0000-000000000000","expiresAt":"2026-01-01T00:00:00Z"}'

POST /v1/keys/{id}/rotate#

Rotate a key (new valid now, old valid for a grace period)

The new key works immediately; the old key keeps working for gracePeriodSeconds (default 24 h, max 30 days).

Authentication: Secret API key · Required scope: keys:manage

Parameters

NameInTypeRequiredDescription
idpathstringyes
Idempotency-Keyheaderstringno

Request body

FieldTypeRequiredDescription
gracePeriodSecondsintegerno

Success response (201)

FieldTypeRequiredDescription
idstring (uuid)yes
namestringyes
prefixstringyes
kindstringno
scopesarray of stringyes
siteIdstring (uuid)no
expiresAtstring (date-time)no
lastUsedAtstring (date-time)no
revokedAtstring (date-time)no
graceUntilstring (date-time)no
secretstringnoShown once, never again.

Response example

{
  "id": "c2a4f0de-7b61-4e3a-9f55-1a8b2c3d4e5f",
  "name": "CI",
  "prefix": "rl_sec_live_",
  "kind": "secret",
  "scopes": [
    "strings:write",
    "bundles:publish"
  ],
  "secret": "rl_sec_live_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
}

Status codes

CodeMeaning
201Success
400Validation failed or malformed request
401Missing or invalid API key
403Insufficient scope, or origin not allowed
404Not found (also returned for other tenants' resources)
409Idempotent request still in progress
413Body too large
415Unsupported media type
422Idempotency-Key reused with a different request, or the import was rejected
429Rate limited (see Retry-After)
500Unexpected error (no details are exposed; quote the reference)

Example

curl -sS -X POST "$RL_API_BASE/v1/keys/${ID}/rotate" \
  -H "Authorization: Bearer $RL_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{"gracePeriodSeconds":1}'

DELETE /v1/keys/{id}#

Revoke a key

Authentication: Secret API key · Required scope: keys:manage

Parameters

NameInTypeRequiredDescription
idpathstringyes
Idempotency-Keyheaderstringno

Status codes

CodeMeaning
204No content
401Missing or invalid API key
403Insufficient scope, or origin not allowed
404Not found (also returned for other tenants' resources)
409Idempotent request still in progress
422Idempotency-Key reused with a different request, or the import was rejected
429Rate limited (see Retry-After)
500Unexpected error (no details are exposed; quote the reference)

Example

curl -sS -X DELETE "$RL_API_BASE/v1/keys/${ID}" \
  -H "Authorization: Bearer $RL_SECRET_KEY"

Discovery#

Optional browser-side reporting of untranslated strings (site key and allowed Origin, off by default).

POST /v1/discover#

Browser snippet reports untranslated strings (site key + allowed Origin; off by default)

Disabled unless the deployment enables it (404). Authenticated by the public site key plus the browser's Origin header, which must be on the site's allowedOrigins.

Authentication: None (public)

Parameters

NameInTypeRequiredDescription
Idempotency-Keyheaderstringno

Request body

FieldTypeRequiredDescription
siteKeystringyes
itemsarray of objectyes
items[].textstringyes
items[].kindenum: text | attrno
items[].contextstringno
items[].urlstring (uri)no

Success response (202)

FieldTypeRequiredDescription
acceptedintegeryes

Status codes

CodeMeaning
202Success
400Validation failed or malformed request
402A plan, allowance or licence blocks this action (see the problem type; D41). Retry-After is set when the allowance resets.
403Insufficient scope, or origin not allowed
404Not found (also returned for other tenants' resources)
413Body too large
415Unsupported media type
422Idempotency-Key reused with a different request, or the import was rejected
429Rate limited (see Retry-After)
500Unexpected error (no details are exposed; quote the reference)
503A plan/quota/licence/suspension check was unavailable (fails closed); retry after Retry-After.

Example

curl -sS -X POST "$RL_API_BASE/v1/discover" \
  -H "Content-Type: application/json" \
  -d '{"siteKey":"string","items":[{"text":"string"}]}'