Documentation

REST API

Authenticate with a JWT or an API key, then call the sync, project, translatable, translation, job and billing endpoints.

Base URL & Authentication

https://api.localingos.com
All endpoints require authentication via either:
Bearer JWTAuthorization: Bearer <token>
API Keyx-api-key: <key>
Public endpoints (no auth required): GET /billing/plans

POST /sync — Push & Pull

Push source strings and pull translations in one request. Only changed content is transferred — the server compares content hashes to skip unchanged items, and only returns translations the client doesn't already have.
Request Body:
{
  "projectId": "a3b7c9d1-4e5f-6a7b-8c9d-0e1f2a3b4c5d",
  "translatables": [
    {
      "id": "homepage.hero.title",
      "locale": "en-US",
      "text": "Welcome to Localingos",
      "description": "Main hero heading",
      "forceReTranslate": false
    }
  ],
  "knownHashes": {                        // from previous sync response (optional)
    "homepage.hero.title": "a1b2c3d4e5f6"
  }
}
Response:
{
  "push": {
    "created": 2,
    "updated": 1,
    "deleted": 0,
    "unchanged": 97
  },
  "translations": [ ... ],               // only keys the client doesn't have
  "hashes": {                             // cache these for next sync
    "homepage.hero.title": "a1b2c3d4e5f6",
    "homepage.hero.subtitle": "f6e5d4c3b2a1"
  },
  "pending": ["new.key.1"],              // keys still being translated
  "nextPullToken": "key1,key2,..."       // null if all translations fit in one response
}
If nextPullToken is present, call POST /sync/pull to fetch remaining translations. Keys not in the payload are auto-deleted from the server (built-in prune).

Fetch the next page of translations when nextPullToken is returned from /sync or a previous /sync/pull call.
Request Body:
{
  "projectId": "a3b7c9d1-4e5f-6a7b-8c9d-0e1f2a3b4c5d",
  "nextPullToken": "key1,key2,key3,..."
}
Response:
{
  "translations": [ ... ],
  "nextPullToken": null                  // null when no more pages
}

GET /project — List all projects for the authenticated user.
// Response
[
  {
    "family": {
      "id": "a3b7c9d1-...",
      "name": "My App",
      "description": "Mobile app translations",
      "locales": ["en-US", "de-DE", "es-ES", "fr-FR"]
    },
    "userAuthorization": "ADMIN"
  }
]
POST /project — Create a new project.
// Request
{
  "name": "My App",
  "description": "Mobile app translations",
  "locales": ["de-DE", "es-ES", "fr-FR"]
}

// Response: same as GET /project item
PUT /project — Update a project.
// Request
{
  "id": "a3b7c9d1-...",
  "name": "My App (Updated)",
  "description": "Updated description",
  "locales": ["de-DE", "es-ES", "fr-FR", "ja-JP"]
}
DELETE /project/{projectId} — Delete a project and user association.

GET /translatable/{projectId} — List all source strings for a family.
// Response
[
  {
    "projectId": "a3b7c9d1-...",
    "id": "homepage.hero.title",        // foreignId (your key)
    "locale": "en-US",
    "text": "Welcome to Localingos",
    "description": "Main hero heading",
    "creationTime": "2026-03-15T10:30:00Z",
    "modificationTime": "2026-03-20T14:22:00Z"
  }
]
POST /translatable — Create or update source strings (upsert by id + projectId).
// Request
{
  "projectId": "a3b7c9d1-...",
  "translatableList": [
    {
      "id": "homepage.hero.title",
      "locale": "en-US",
      "text": "Welcome to Localingos",
      "description": "Main hero heading on the landing page"
    },
    {
      "id": "homepage.hero.subtitle",
      "locale": "en-US",
      "text": "Developer-first localization",
      "description": "Sub-heading below the main title"
    }
  ]
}

GET /translation/{projectId} — List all translations for a family.
// Response
[
  {
    "foreignId": "homepage.hero.title",
    "locale": "de-DE",
    "text": "Willkommen bei Localingos"
  },
  {
    "foreignId": "homepage.hero.title",
    "locale": "es-ES",
    "text": "Bienvenido a Localingos"
  }
]
GET /translation/{projectId}/{foreignId} — Get translations for a specific key.
// Response: same shape as above, filtered to one foreignId

POST /translation-jobs/project/{projectId} — List jobs for a project (paginated).
// Request
{ "pageSize": 100, "nextToken": null }

// Response
{
  "jobs": [
    {
      "id": "abc123#2026-03-20T14:22:00Z",
      "jobType": "NEW",
      "translatableId": "uuid-...",
      "projectId": "a3b7c9d1-...",
      "jobState": "DONE",           // QUEUED | IN_PROGRESS | DONE | FAILED | BLOCKED
      "stateReason": null,           // reason for FAILED/BLOCKED
      "sourceLocale": "en-US",
      "targetLocales": ["de-DE", "es-ES"],
      "creationTime": "2026-03-20T14:22:00Z",
      "modificationTime": "2026-03-20T14:22:05Z"
    }
  ],
  "nextToken": "...",
  "hasMore": true,
  "totalCount": 250
}
POST /translation-jobs/project/{projectId}/retry-all — Retry all FAILED and BLOCKED jobs.
// Response
{
  "jobs": [...],          // retried jobs with updated states
  "success": true,
  "message": "Retried 5 jobs: 5 successfully queued, 0 failed to queue",
  "totalProcessed": 5,
  "totalSucceeded": 5,
  "totalFailed": 0
}
POST /translation-jobs/job/{id}/{jobType}/retry — Retry a single job.

POST /api/api-keys — Create a new API key.
// Request (optional)
{ "name": "CI/CD Pipeline" }

// Response
{
  "apiKey": "dGhpcyBpcyBhIHNlY3VyZSBrZXk...",
  "userId": "84e8c458-...",
  "name": "CI/CD Pipeline",
  "creationTime": "2026-03-20T14:22:00Z"
}
Warning: The API key is shown only once. Store it securely.
GET /api/api-keys — List all API keys (keys are masked).
DELETE /api/api-keys/{apiKey} — Revoke an API key.

GET /billing/plans — List available plans. No auth required.
// Response
[
  { "key": "starter", "name": "Starter", "monthlyPrice": 9, "yearlyIncludedWords": 50000 },
  { "key": "growth", "name": "Growth", "monthlyPrice": 29, "yearlyIncludedWords": 250000 },
  { "key": "scale", "name": "Scale", "monthlyPrice": 79, "yearlyIncludedWords": 1000000 }
]
GET /billing/subscription — Get current subscription and trial status.
// Response
{
  "billingAccountId": "d29229b6-...",
  "accessMode": "PAID",              // TRIAL | PAID | READ_ONLY
  "trialStatus": "CONVERTED",        // NOT_STARTED | ACTIVE | EXPIRED | CONVERTED
  "activePlan": "growth",
  "planDisplayName": "Growth",
  "subscriptionStatus": "active",
  "monthlyPrice": 99,
  "yearlyIncludedWords": 150000,
  "yearlyUsedWords": 42000,
  "yearlyRemainingWords": 108000,
  "percentUsed": 28.0,
  "currentPeriodStart": "2026-01-10T00:00:00Z",
  "currentPeriodEnd": "2027-01-10T00:00:00Z"
}
GET /billing/usage — Get current period usage details.