API Reference
A small, API-key-authenticated surface for pulling and pushing a single project's translations — built for CI pipelines, build-time codegen, and pull/push scripts. It mirrors the Localizely API, so many existing integrations work by only swapping the base URL.
Base URL
https://localizator.carcutter.ioAuthentication
Every request must include a project API key, created from that project's Settings → API keys card in the app. Send it in the X-Api-Token header (the Localizely-compatible form), or as a standard Authorization: Bearer header — either works.
X-Api-Token: lt_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # or Authorization: Bearer lt_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
A key is scoped to the single project it was created for. Requests with a missing or invalid token get a 401; a token that belongs to a different project gets the same 404a nonexistent project would, so a leaked token can't be used to probe which project ids exist.
Glossary
- Project
- A workspace containing one set of translation keys and one or more languages. Every API call is scoped to a single project via its {projectId}.
- Locale / language code
- An identifier for a target language, e.g.
en,de,fr-CA. Wherever the API acceptslang_code/lang_codes, either the locale itself or the underlying language's internal id works. - Translation key
- The stable identifier for one translatable string, e.g.
greetingornav.home. Dot-separated segments are treated as nested paths in JSON (see nested vs. flat JSON). - API key
- A per-project secret (prefixed
lt_) created from Settings → API keys. Sent asX-Api-TokenorAuthorization: Bearerto authenticate every request. - Overwrite
- Import option controlling whether an existing non-empty translation value is replaced (
overwrite: true, the default) or left untouched (false— only blanks get filled in). - ARB
- Application Resource Bundle — Flutter's JSON-based localization file format (.arb), with @@locale and @key metadata entries alongside the translations.
- Nested vs. flat JSON
- Nested JSON mirrors dot-path keys as real object nesting (
{ nav: { home: ... } }); flat JSON keeps each key as a single top-level dot-path string ({ "nav.home": ... }). Controlled by thenestedquery param on download. - Import job
- An audit record created every time translations are loaded via POST /files or the app's import UI: source file name, format, and how many keys were added/updated. Feeds the project's Activity tab.
Errors
Errors are always a JSON body shaped { "error": string } (validation errors also include an issues array from the request schema).
| Status | Meaning |
|---|---|
| 400 | Malformed request (missing field, unparsable file content). |
| 401 | Missing, invalid, or revoked API token. |
| 404 | Project or locale not found (or the token belongs to a different project). |
| 422 | Request body failed schema validation. |
| 503 | Database unreachable or not configured. |
Project status
Lists the project's languages, so tooling can discover which locale codes are available before downloading or uploading. The default/source language is listed first.
curl -H "X-Api-Token: $API_TOKEN" \ "https://localizator.carcutter.io/api/v1/projects/$PROJECT_ID/status"
Response
{
"id": "cmq6pqqdy04v8tkxfp4vknobz",
"name": "Demo Project",
"defaultLocale": "en",
"languages": [
{ "langCode": "en", "name": "English", "isDefault": true },
{ "langCode": "de", "name": "German", "isDefault": false }
]
}Download a locale
Downloads one locale's translations as a file body (not wrapped in JSON metadata) — a JSON map or a Flutter ARB file.
| Query param | Required | Description |
|---|---|---|
| lang_codes | yes | A single locale code (e.g. en, fr-CA). Multiple locales per request aren't supported. |
| type | no | json (default) or arb (Flutter). |
| export_empty_as | no | main falls empty values back to the source language; default keeps them blank. |
| nested | no | false emits a flat dot-path object (JSON only). |
# Fetch a locale as nested JSON (the default) curl -H "X-Api-Token: $API_TOKEN" \ "https://localizator.carcutter.io/api/v1/projects/$PROJECT_ID/files/download?lang_codes=en" # Flat, dot-path JSON curl -H "X-Api-Token: $API_TOKEN" \ "https://localizator.carcutter.io/api/v1/projects/$PROJECT_ID/files/download?lang_codes=en&nested=false" # Flutter ARB, filling empty values from the source language curl -H "X-Api-Token: $API_TOKEN" \ "https://localizator.carcutter.io/api/v1/projects/$PROJECT_ID/files/download?lang_codes=fr&type=arb&export_empty_as=main" \ -o app_fr.arb
Load (upload) a locale
Imports translations for one locale — the push counterpart to download. New keys are created automatically; by default existing non-empty values are overwritten (set overwrite: false to only fill in blanks). Each call archives the submitted content, writes an import joband activity-log entry (visible on the project's Activity tab), and triggers a background Google Drive sync if one is connected.
Send either a file upload or a JSON body — whichever is more convenient for your client.
Option A — multipart/form-data
| Field | Required | Description |
|---|---|---|
| file | yes | The JSON or ARB file to import. |
| lang_code | yes | Target locale code or language id. |
| format | no | JSON or ARB; guessed from the file name if omitted. |
| overwrite | no | "true" (default) or "false". |
curl -X POST "https://localizator.carcutter.io/api/v1/projects/$PROJECT_ID/files" \ -H "X-Api-Token: $API_TOKEN" \ -F "file=@de.json" \ -F "lang_code=de"
Option B — JSON body, inline translations
A flat or nested map of translation keys to values, applied the same way a JSON file import would be (see nested vs. flat JSON).
curl -X POST "https://localizator.carcutter.io/api/v1/projects/$PROJECT_ID/files" \
-H "X-Api-Token: $API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"lang_code": "de",
"translations": { "greeting": "Hallo", "nav": { "home": "Startseite" } }
}'Option C — JSON body, raw file content
Send the file's text as a string — useful when you already have a JSON or ARB document in hand and don't want to multipart-encode it.
curl -X POST "https://localizator.carcutter.io/api/v1/projects/$PROJECT_ID/files" \
-H "X-Api-Token: $API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"lang_code": "de",
"format": "JSON",
"content": "{\"greeting\": \"Hallo\"}"
}'Response (all three options)
{
"added": 12,
"updated": 3,
"total": 15,
"blobUrl": "https://...blob.vercel-storage.com/imports/..."
}blobUrlis an empty string when the deployment doesn't have Vercel Blob storage configured — the import still succeeds either way.