REST and GraphQL API
Everything the web application does goes through the same public API you can call yourself. There are two ways in — a REST API for automation and a GraphQL endpoint that the application itself uses — and both sit behind the same authentication and the same permission checks.
Base URL: https://api.ownlate.com
Authentication
Section titled “Authentication”| Credential | Looks like | Used for |
|---|---|---|
| API key | own_… | Server-to-server calls, CI, scripts |
| SDK token | sdk_… | The browser SDK, one project only |
| OAuth access token | opaque | The MCP server and third-party apps |
| Session cookie | — | The web application in your browser |
Pass a key as a bearer token:
curl "https://api.ownlate.com/v1/workspaces" \ -H "Authorization: Bearer $OWNLATE_API_KEY"Create keys under Profile → API keys. A key is shown once, at creation, and only its prefix afterwards. Each key carries:
- Scopes — the permission codes it may exercise, which can only narrow what you already hold, never widen it.
- An optional expiry — after which the key stops working.
Revoking a key takes effect immediately. See Members and access for the permission codes themselves.
How permission is decided
Section titled “How permission is decided”For every call, the server works out which workspace it concerns, then checks what the caller holds against it:
- The workspace comes from the path. Query strings and request bodies are not considered when resolving it, so an endpoint whose path names no workspace refuses with
Workspace ID is requiredrather than guessing. - An API key or OAuth token narrows further: a permission outside its scopes, or a workspace outside those it was issued for, is refused before the workspace is even asked.
- An anonymous caller gets what a viewer would see — and no more.
- An open project additionally accepts suggestions from anybody signed in.
Errors
Section titled “Errors”Failures come back as JSON with the status repeated in the body:
{ "message": "Forbidden", "error": "Forbidden", "statusCode": 403 }| Status | Means |
|---|---|
400 | The request did not validate |
401 | No credential, or one that is no longer good |
403 | Authenticated, but not allowed to do this |
404 | No such object, or no such route |
409 | The object is not in a state that allows this — approving something already approved |
Request bodies are limited to 1 MB. For files larger than that, split the upload by file.
Interactive reference
Section titled “Interactive reference”The generated OpenAPI document is served at /swagger-json, and the application renders it at platform.ownlate.com/docs/swagger. It is generated from the running server, so it is never out of date with respect to what is deployed.
Endpoints
Section titled “Endpoints”Workspaces and members
Section titled “Workspaces and members”| Method | Path |
|---|---|
GET POST | /v1/workspaces |
GET PUT | /v1/workspaces/{workspaceId} |
GET | /v1/workspaces/{workspaceId}/audit-log |
POST | /v1/workspaces/{workspaceId}/sync-word-usage |
GET | /v1/workspaces/{workspaceId}/users/me/permissions |
GET POST | /v1/workspaces/{workspaceId}/members |
DELETE | /v1/workspaces/{workspaceId}/members/{userId} |
GET | /v1/workspaces/users/lookup |
GET PUT | /v1/workspaces/levels/{level} |
GET POST | /v1/workspaces/api-keys |
DELETE | /v1/workspaces/api-keys/{keyId} |
GET | /v1/users/me |
Projects
Section titled “Projects”| Method | Path |
|---|---|
GET POST | /v1/workspaces/{workspaceId}/projects |
GET PUT DELETE | /v1/workspaces/{workspaceId}/projects/{id} |
PUT | /v1/workspaces/{workspaceId}/projects/{id}/restore |
DELETE | /v1/workspaces/{workspaceId}/projects/{id}/permanent |
DELETE on a project archives it; permanent destroys an archived one.
| Method | Path |
|---|---|
GET POST | /v1/workspaces/{workspaceId}/translation-files |
POST | /v1/workspaces/{workspaceId}/translation-files/upload |
PUT DELETE | /v1/workspaces/{workspaceId}/translation-files/{id} |
POST | /v1/workspaces/{workspaceId}/translation-files/rename-folder |
POST | /v1/workspaces/{workspaceId}/translation-files/merge-duplicates |
Segments and translations
Section titled “Segments and translations”| Method | Path |
|---|---|
GET POST | /v1/workspaces/{workspaceId}/segments |
GET DELETE | /v1/workspaces/{workspaceId}/segments/{id} |
PUT | /v1/workspaces/{workspaceId}/segments/{id}/translate |
PUT | /v1/workspaces/{workspaceId}/segments/{id}/draft |
PUT | /v1/workspaces/{workspaceId}/segments/{id}/source-text |
PUT | /v1/workspaces/{workspaceId}/segments/{id}/translations/{language}/review |
PUT | /v1/workspaces/{workspaceId}/segments/{id}/translations/{language}/approve |
PUT | /v1/workspaces/{workspaceId}/segments/{id}/translations/{language}/reject |
POST | /v1/workspaces/{workspaceId}/segments/{id}/auto-translate |
GET | /v1/workspaces/{workspaceId}/segments/{id}/qa |
POST | /v1/workspaces/{workspaceId}/segments/approve-all |
POST | /v1/workspaces/{workspaceId}/segments/reject-all |
POST | /v1/workspaces/{workspaceId}/segments/pre-translate |
GET | /v1/workspaces/{workspaceId}/segments/progress |
GET | /v1/workspaces/{workspaceId}/segments/analytics |
GET | /v1/workspaces/{workspaceId}/segments/by-keys |
GET | /v1/workspaces/{workspaceId}/segments/translation-memory |
GET | /v1/workspaces/{workspaceId}/segments/export |
GET | /v1/workspaces/{workspaceId}/segments/export-zip |
Glossary, comments and history
Section titled “Glossary, comments and history”| Method | Path |
|---|---|
GET POST | /v1/workspaces/{workspaceId}/glossary |
PUT DELETE | /v1/workspaces/{workspaceId}/glossary/{id} |
GET | /v1/workspaces/{workspaceId}/glossary/matches |
GET POST | /v1/workspaces/{workspaceId}/comments |
DELETE | /v1/workspaces/{workspaceId}/comments/{id} |
GET | /v1/workspaces/{workspaceId}/translation-history/{segmentId} |
Releases and distribution
Section titled “Releases and distribution”| Method | Path |
|---|---|
GET POST | /v1/workspaces/{workspaceId}/releases |
DELETE | /v1/workspaces/{workspaceId}/releases/{id} |
GET | /v1/workspaces/{workspaceId}/releases/distribution |
POST | /v1/workspaces/{workspaceId}/releases/distribution/regenerate |
Integrations
Section titled “Integrations”| Method | Path |
|---|---|
POST | /v1/workspaces/{workspaceId}/integrations |
GET | /v1/workspaces/{workspaceId}/integrations/by-project/{projectId} |
GET PUT DELETE | /v1/workspaces/{workspaceId}/integrations/{id} |
PATCH | /v1/workspaces/{workspaceId}/integrations/{id}/activate |
PATCH | /v1/workspaces/{workspaceId}/integrations/{id}/pause |
PATCH | /v1/workspaces/{workspaceId}/integrations/{id}/sync |
PATCH | /v1/workspaces/{workspaceId}/integrations/{id}/test |
POST | /v1/workspaces/{workspaceId}/integrations/test-direct |
POST | /v1/workspaces/{workspaceId}/integrations/{id}/create-pr |
Plans and billing
Section titled “Plans and billing”| Method | Path |
|---|---|
GET | /v1/plans |
GET | /v1/payment/providers |
GET | /v1/workspaces/{workspaceId}/subscription |
PUT | /v1/workspaces/{workspaceId}/subscription/plan |
POST | /v1/workspaces/{workspaceId}/subscription/checkout |
POST | /v1/workspaces/{workspaceId}/subscription/portal |
Languages
Section titled “Languages”| Method | Path |
|---|---|
GET POST | /v1/languages |
DELETE | /v1/languages/{code} |
Public endpoints
Section titled “Public endpoints”These need no credential at all. They serve public projects and OTA distributions.
| Method | Path | Returns |
|---|---|---|
GET | /public/v1/projects | Public projects of a workspace |
GET | /public/v1/projects/{id} | One public project |
GET | /public/v1/segments/progress | Progress of a public project |
GET | /public/v1/segments/translations-map | Every translation of a public project, grouped by file and language |
GET | /public/v1/ota/{accessKey}/manifest | Latest release version and languages |
GET | /public/v1/ota/{accessKey}/bundles | Bundle for every language |
GET | /public/v1/ota/{accessKey}/bundles/{language} | Bundle for one language |
GET | /public/v1/plans | Plans with prices |
GET | /public/v1/workspaces/{workspaceId} | Public workspace details |
The SDK endpoints — /public/v1/sdk/segments and /public/v1/sdk/segments/{id}/translations/{lang} — need an SDK token rather than an API key. See SDK and clients.
GraphQL
Section titled “GraphQL”POST /graphql carries the same operations the web application uses, which is a superset of what REST exposes: invites, tasks, suggestions, notifications, QA rules, SDK tokens, translation memory entries and the analytics queries.
curl -X POST https://api.ownlate.com/graphql \ -H "Authorization: Bearer $OWNLATE_API_KEY" \ -H 'Content-Type: application/json' \ -d '{"query":"query($id:ID!){ project(id:$id){ name progress { language progress } } }","variables":{"id":"…"}}'Two things to know before you point a client at it:
- The content type matters. A request that looks like it could have come from an HTML form —
application/x-www-form-urlencoded,multipart/form-dataortext/plain— is rejected as a possible cross-site request unless it names an operation in thex-apollo-operation-nameheader. Sendapplication/jsonand this never comes up. - Permission is resolved from arguments. Pass
workspaceIdwhere the schema asks for it, including insideinputobjects; a mutation that leaves it out cannot be authorised.