openapi: 3.1.0 info: title: transglot API version: v1 summary: Push source strings, pull translations, run translation and quality checks, publish to the CDN, manage the glossary and webhooks. description: >- The transglot API is a versioned HTTP API scoped to one project. Every request under `/v1` authenticates with a project deploy token sent as `Authorization: Bearer `, and the token decides which project the request acts on, so no URL carries a workspace or project identifier. Each operation requires one ability on the token, listed on the operation as `x-required-ability`. Request and response bodies are JSON unless an operation says otherwise. Errors are RFC 7807 problem documents with `Content-Type: application/problem+json`; branch on `type`. Requests are rate limited per token, and a limited request answers `429` with a `Retry-After` header. `/v1` changes additively: new endpoints and new response fields ship inside it, and a field you already parse does not change shape or disappear. API access needs the Starter plan or higher. contact: name: transglot url: https://transglot.ai servers: - url: https://api.transglot.ai description: Production security: - deployToken: [] tags: - name: Project description: The project the token belongs to, its languages and their progress. - name: Push and pull description: Upload a locale file into the project, and download a locale as a file. - name: Translation description: Start an AI translation run with Glossa. - name: Batches description: Watch, retry and cancel translation runs. - name: Translations (single values) description: Read and write individual translation values by key name. - name: Quality description: Start a quality check over translated strings. - name: CDN description: >- Publish a locale as an immutable runtime bundle, and read published bundles with a CDN key. - name: Glossary description: List, create, update, delete, import, export and extract glossary terms. - name: Webhooks description: >- Subscribe an HTTPS endpoint to project events, and read the event catalog with sample payloads. components: securitySchemes: deployToken: type: http scheme: bearer description: >- A project deploy token, minted in the console under Settings, Developer, API tokens. Send the whole value, including the numeric prefix before the `|`. A token carries a set of abilities (`push`, `pull`, `manage`, `read`, `write`) and each operation requires one of them. Tokens do not inherit from each other: a `manage` token cannot read the glossary unless it also has `read`. cdnKeyHeader: type: apiKey in: header name: X-Transglot-Cdn-Key description: >- A read-only CDN key (`taicdn_...`), minted under Settings, Developer, Runtime delivery (CDN). It can only read this project's published bundles. Prefer the header; it keeps the key out of URLs and logs. cdnKeyQuery: type: apiKey in: query name: key description: The same CDN key, as a query parameter, for clients that cannot set a header. headers: RetryAfter: description: Seconds to wait before retrying. schema: type: integer example: 42 RateLimitLimit: description: The number of requests the limit allows per minute. schema: type: integer example: 60 RateLimitRemaining: description: Requests left in the current minute. schema: type: integer example: 0 RateLimitReset: description: Unix timestamp, in seconds, at which the limit resets. schema: type: integer example: 1791820920 ETag: description: A strong validator for the body. Send it back as `If-None-Match` to get a `304`. schema: type: string example: '"9f2c4e0b7a1d5e3f8c6b2a4d0e9f1c7b3a5d8e2f4c6b0a9d7e1f3c5b8a2d4e6f"' parameters: BatchId: name: batch in: path required: true description: The batch id, as returned by `POST /v1/translate`, `GET /v1/batches` or a push. schema: type: integer example: 4821 TermId: name: termId in: path required: true description: The glossary term id. schema: type: integer example: 311 WebhookId: name: webhook in: path required: true description: The webhook endpoint id. schema: type: integer example: 7 CdnProject: name: project in: path required: true description: >- The numeric project id. It must be the project the CDN key belongs to; any other id answers `404`. schema: type: integer example: 12 CdnLocale: name: locale in: path required: true description: A locale configured on the project, for example `fr` or `pt-BR`. schema: type: string example: fr CdnFormat: name: format in: query required: false description: >- Optional assertion of the published format. A version is published in exactly one format; naming a different one answers `404 not-published`, and an unknown format answers `422 invalid-format`. schema: $ref: '#/components/schemas/FileFormat' IfNoneMatch: name: If-None-Match in: header required: false description: An `ETag` from an earlier response. When it still matches, the answer is `304` with no body. schema: type: string schemas: Problem: type: object description: >- An RFC 7807 problem document. Every error on the API host has this shape and the `application/problem+json` content type. Some types add extension members, described on the operations that can return them. required: [type, title, status, detail] properties: type: type: string description: >- A relative URI naming the problem, `/problems/`. Branch on this, not on `detail`. example: /problems/not-found title: type: string description: The slug in words, with hyphens replaced by spaces and the first letter capitalised. example: Not found status: type: integer description: The HTTP status code, repeated. example: 404 detail: type: string description: A sentence for a person reading a log. It can change; do not parse it. example: Not found. additionalProperties: true ValidationProblem: allOf: - $ref: '#/components/schemas/Problem' - type: object properties: errors: type: object description: Field name to the list of messages for that field. additionalProperties: type: array items: type: string MissingAbilityProblem: allOf: - $ref: '#/components/schemas/Problem' - type: object properties: ability: type: [string, 'null'] description: >- The ability the token lacks. For an operation that accepts any of `push`, `pull` or `manage`, this names the first of them, `push`. example: manage ActiveBatchProblem: allOf: - $ref: '#/components/schemas/Problem' - type: object properties: batch_id: type: integer description: The id of the batch that is already running. Poll it instead of starting another. example: 4820 QuotaProblem: allOf: - $ref: '#/components/schemas/Problem' - type: object properties: quota: type: object properties: reason: type: string enum: [plan_allowance, spend_cap, overage_paused] description: >- `plan_allowance`: the account has no AI words left this cycle. `spend_cap`: translation beyond the plan is paused by the spend cap. `overage_paused`: translation beyond the plan is paused. scope: type: string enum: [account] description: Always `account`; the words are the account's, whichever workspace asked. requested: type: integer description: The number of words this request needed. resets_at: type: [string, 'null'] format: date-time description: When the refusal lifts, when that is known. CapProblem: allOf: - $ref: '#/components/schemas/Problem' - type: object properties: cap: type: object properties: kind: type: string enum: [suggest, assistant, extract] scope: type: string enum: [account, workspace] description: Whether the account's total or this workspace's share ran out. resets_at: type: string format: date-time PlanLimitProblem: allOf: - $ref: '#/components/schemas/Problem' - type: object properties: resource: type: string description: The plan feature or limit that refused the request. example: quality_mode cap: type: [integer, 'null'] description: The plan's limit, for a counted limit; `null` for a feature the plan does not include. upgrade_hint: type: string example: Upgrade your plan to use this feature. NestedKeyCollisionProblem: allOf: - $ref: '#/components/schemas/Problem' - type: object properties: keys: type: array description: The key names that cannot coexist in a nested format, for example `a` and `a.b`. items: type: string FileFormat: type: string description: A file format transglot reads and writes. enum: - json_flat - json_nested - android_xml - ios_strings - ios_stringsdict - flutter_arb - laravel_php - laravel_json - xliff_12 - ios_xcstrings - gettext_po - yaml - csv - xlsx - xliff_20 - java_properties - resx - markdown - unity_csv - unreal_po Progress: type: object description: How far one target locale has got. `translated` and `humanBacked` are derived from the counts. properties: total: type: integer description: Strings expected in this locale. reviewed: type: integer description: Strings a person has approved. human: type: integer description: Strings a person has written or edited and nobody has approved yet. ai: type: integer description: Strings holding a Glossa draft nobody has edited or approved. empty: type: integer description: Strings with no value yet. translated: type: integer description: '`reviewed + human + ai`: strings holding any value.' humanBacked: type: integer description: '`reviewed + human`: strings a person stands behind.' percent: type: integer description: '`translated` as a whole percentage of `total`, 0 to 100. A locale expecting nothing reads 0.' LocaleRow: type: object properties: locale: type: string example: fr name: type: string example: French rtl: type: boolean description: Whether the language is written right to left. is_source: type: boolean progress: description: Progress for a target locale; `null` on the source locale. oneOf: - $ref: '#/components/schemas/Progress' - type: 'null' Project: type: object properties: id: type: integer example: 12 name: type: string example: Acme Web slug: type: string example: acme-web source_locale: type: string example: en locales: type: array description: Every language on the project, source included, sorted by locale. items: $ref: '#/components/schemas/LocaleRow' keys_count: type: integer description: The number of translation keys in the project. message_syntax: type: string enum: [legacy, auto, icu] description: How the project reads message syntax when it checks strings. icu_dialect: type: string enum: [icu4c, flutter] auto_translate: type: boolean description: Whether a source push starts a translation run on arrival. first_run_pending: type: boolean description: >- Whether the project's first translation run is still waiting to be confirmed. While it is, a source push does not start a run. Batch: type: object description: A translation run. properties: id: type: integer example: 4821 status: type: string enum: [pending, processing, completed, completed_with_errors, failed, cancelled] description: >- `pending` and `processing` are active; the other four are final. Only one batch per project is active at a time. trigger: type: string enum: [manual_missing, manual_selected, auto_edit, language_added, retry_failed, push] description: What started the run. total: type: integer description: Key and locale pairs sent for translation. completed: type: integer description: Pairs the run finished processing. failed: type: integer description: Pairs that failed. skipped: type: integer description: >- Pairs the run covered and will not write. A translation you have edited or reviewed is never overwritten by AI; such pairs are counted here. skipped_reasons: type: [object, 'null'] description: >- Skipped pairs by reason. `human_value_stands`: a person's translation is in place. `human_value_stale`: a person's translation is in place and the source has changed since, so only a person can update it. `source_moved`: the source changed while the run was in progress; running again fixes it. additionalProperties: type: integer example: human_value_stale: 12 tm_served: type: integer description: Pairs answered from translation memory. They are not part of `total`. language_breakdown: type: [object, 'null'] description: Pairs per target locale. additionalProperties: type: integer example: fr: 120 de: 120 started_at: type: [string, 'null'] format: date-time finished_at: type: [string, 'null'] format: date-time example: id: 4821 status: processing trigger: manual_missing total: 240 completed: 96 failed: 0 skipped: 12 skipped_reasons: human_value_stale: 12 tm_served: 37 language_breakdown: fr: 120 de: 120 started_at: '2026-10-12T09:39:13+00:00' finished_at: null BatchFailure: type: object properties: key: type: string example: checkout.error.declined locale: type: string example: de error: type: [string, 'null'] description: The last error recorded for this pair. BatchWithFailures: allOf: - $ref: '#/components/schemas/Batch' - type: object properties: failures: type: array description: Failed pairs, ordered by when they were queued, at most 100. items: $ref: '#/components/schemas/BatchFailure' PushConflict: type: object properties: key: type: string locale: type: string reason: type: string description: >- `human-edited`: a target value was not written because a person has edited or reviewed that translation. `plural-shape-mismatch`: the file's entry and the key disagree on whether it is plural. `key-name-too-long`: the key name is too long to store. example: human-edited PushResult: type: object properties: metadata: type: object description: Present only when the push carried a metadata sidecar. properties: descriptions_updated: type: integer max_lengths_updated: type: integer unknown_keys: type: array items: type: string unknown_keys_count: type: integer keys_created: type: integer description: Keys created by a source push. keys_deleted: type: integer description: Keys deleted by a source push with `mode=sync_removals`. source_updated: type: integer description: Source strings whose value changed. translations_written: type: integer description: Target values written by a target push. conflicts: type: array items: $ref: '#/components/schemas/PushConflict' unknown_keys: type: array description: Keys in a target file that do not exist in the project. A target push never creates keys. items: type: string warnings: type: array description: Human-readable warnings for a log. items: type: string batch: description: The translation run this push started, or `null`. oneOf: - $ref: '#/components/schemas/Batch' - type: 'null' quota_exceeded: type: boolean description: >- `true` when the push was applied but its translation run was not started because the account has no AI words left or a spend cap applies. translation_paused: type: [string, 'null'] description: >- A code naming any other reason the push's translation run was not started, for example `overage-paused` or `ai-paused`; `null` when nothing stopped it. hold: type: string enum: [held, nothing-to-hold] description: >- Present only when the request sent `hold=1`. `held` means a run was due and is waiting for the project's first-run confirmation. import: type: object description: Present only when the request sent `import=repo`. properties: entries: type: integer written: type: integer unchanged: type: integer skipped_empty: type: integer skipped_same_as_source: type: integer TranslateRequest: type: object required: [scope] properties: scope: type: string enum: [missing, selected, stale, all] description: >- `missing` and `all`: every pair with no value, or whose value was written against an older source. `stale`: only pairs that have a value written against an older source. `selected`: like `missing`, limited to `key_ids`. key_ids: type: array maxItems: 2000 description: Limit the run to these key ids. Honoured with any scope. items: type: integer locales: type: array maxItems: 200 description: Limit the run to these target locales. Omit for every target locale. items: type: string maxLength: 35 QaRunRequest: type: object required: [scope] properties: scope: type: string enum: [missing, selected, stale, all] description: >- `missing`: translations never checked. `stale`: translations whose source changed since their last check. `all` and `selected`: every translation in scope. A translation already checked whose source and value have not changed since is not checked again. `selected` with no `key_ids` checks nothing. key_ids: type: array maxItems: 2000 items: type: integer locales: type: array maxItems: 200 items: type: string maxLength: 35 QaRunHandle: type: object properties: dispatched_jobs: type: integer description: How many groups of strings were queued for checking. rows: type: integer description: How many translations will be checked. example: dispatched_jobs: 3 rows: 74 Cell: type: object properties: id: type: [integer, 'null'] description: The translation's id, or `null` when no value exists yet. content: type: [string, 'null'] description: The value of a simple key. plural_forms: type: [object, 'null'] description: The value of a plural key, by CLDR plural category. additionalProperties: type: string state: type: [string, 'null'] enum: [ai_translated, human_edited, reviewed, null] description: >- `ai_translated`: a Glossa draft. `human_edited`: written or edited by a person or through the API. `reviewed`: approved. stale: type: boolean description: Whether the source has changed since this value was written. TargetCell: allOf: - $ref: '#/components/schemas/Cell' - type: object properties: content_hash: type: [string, 'null'] description: >- A hash of the current value. Send it back as `expected_hash` on a write to make the write conditional. needs_review: type: boolean description: Whether the last quality check flagged this translation. qa_score: type: [integer, 'null'] description: The score from the last quality check, or `null` if it has not been checked. mqm_score: type: [integer, 'null'] description: The quality score shown on the translation in the editor, or `null`. qa_findings: type: [array, 'null'] description: What the last quality check found, or `null`. items: type: object properties: category: type: string severity: type: string message: type: string suggestion: type: string ai_confidence: type: [integer, 'null'] description: The confidence score Glossa recorded for a draft, or `null`. authored_by_you: type: boolean description: Always `false` for a deploy token, which has no signed-in person. SourceTokens: type: object description: >- The source split into text and placeholder spans, for highlighting. Offsets are UTF-16 code units. A plural source carries one span list per category under `forms`. properties: kind: type: string enum: [simple, plural] spans: type: array items: $ref: '#/components/schemas/Span' forms: type: object additionalProperties: type: array items: $ref: '#/components/schemas/Span' Span: type: object properties: start: type: integer end: type: integer kind: type: string enum: [text, placeholder] TranslationRow: type: object description: One key, its source value and its value in the requested locale. properties: id: type: integer description: The key id. Use it in `key_ids` on `POST /v1/translate` and `POST /v1/qa/run`. example: 9132 name: type: string example: checkout.submit description: type: [string, 'null'] example: Button that places the order. is_plural: type: boolean max_length: type: [integer, 'null'] tags: type: array description: Always an empty list on these endpoints. items: type: object properties: id: type: integer name: type: string source_tokens: $ref: '#/components/schemas/SourceTokens' source: $ref: '#/components/schemas/Cell' target: $ref: '#/components/schemas/TargetCell' example: id: 9132 name: checkout.submit description: Button that places the order. is_plural: false max_length: 24 tags: [] source_tokens: kind: simple spans: - start: 0 end: 9 kind: text source: id: 50211 content: Pay now plural_forms: null state: human_edited stale: false target: id: 50388 content: Payer maintenant plural_forms: null state: ai_translated stale: false content_hash: 3b5c0f6e1d7a9c2e4f8b0a6d2c4e6f8a1b3d5f7a9c1e3b5d7f9a2c4e6b8d0f1a needs_review: false qa_score: null mqm_score: null qa_findings: null ai_confidence: 92 authored_by_you: false TranslationWrite: type: object required: [key, locale] description: >- Send `content` for a simple key or `plural_forms` for a plural key. The field is required even when empty: an empty string clears the value, and omitting the field is refused so a request cannot blank a translation by accident. properties: key: type: string maxLength: 500 example: checkout.submit locale: type: string maxLength: 35 example: fr content: type: [string, 'null'] maxLength: 10000 example: Payer maintenant plural_forms: type: object description: Values by CLDR plural category. additionalProperties: type: [string, 'null'] maxLength: 10000 expected_hash: type: [string, 'null'] maxLength: 64 description: >- Optional. The `content_hash` you last read. When it no longer matches, the write is refused with `409` and the current row. `null` asserts that no value exists yet. RowConflict: type: object description: The body of a conditional write that lost. Not a problem document. properties: error: type: string enum: [row-changed] message: type: string example: This row changed since you loaded it. Refresh and try again. row: $ref: '#/components/schemas/TranslationRow' CdnPublishResult: type: object properties: locale: type: string example: fr version: type: integer description: The published version number. Versions only increase. example: 14 format: $ref: '#/components/schemas/FileFormat' content_hash: type: string description: SHA-256 of the bundle body. It is the bundle's `ETag`. key_count: type: integer description: Entries in the bundle. omitted_invalid_icu_keys: type: integer description: >- Translations left out of the bundle because their message syntax would fail at runtime. They are not counted in `key_count`. byte_size: type: integer created: type: boolean description: '`false` when the content was identical to the live version, so no new version was minted.' published_at: type: string format: date-time immutable_url: type: string format: uri description: The URL of this exact version. Its response never changes. latest_url: type: string format: uri description: The URL that always serves the newest published version. example: locale: fr version: 14 format: json_flat content_hash: 9f2c4e0b7a1d5e3f8c6b2a4d0e9f1c7b3a5d8e2f4c6b0a9d7e1f3c5b8a2d4e6f key_count: 1204 omitted_invalid_icu_keys: 0 byte_size: 48213 created: true published_at: '2026-10-12T09:45:02+00:00' immutable_url: https://api.transglot.ai/v1/cdn/12/fr/v14 latest_url: https://api.transglot.ai/v1/cdn/12/fr GlossaryTerm: type: object properties: id: type: integer example: 311 source_term: type: string example: Checkout source_normalized: type: string description: The source term as it is matched; lowercased unless `case_sensitive`. example: checkout part_of_speech: type: [string, 'null'] example: noun notes: type: [string, 'null'] case_sensitive: type: boolean do_not_translate: type: boolean description: The term stays in the source language in every translation. forbidden: type: boolean description: The term must not appear in translations. status: type: string enum: [active, pending, rejected] description: >- `active` terms apply to translation. `pending` terms are candidates proposed by glossary extraction. `rejected` candidates are kept so they are not proposed again. confidence: type: [number, 'null'] description: Set on candidates proposed by extraction; `null` on terms written by hand. translations: type: object description: Approved translations of the term, by locale. additionalProperties: type: string example: fr: Paiement de: Kasse created_by: type: [string, 'null'] description: What created the term; `api` for a term created through this API. example: api created_at: type: [string, 'null'] format: date-time updated_at: type: [string, 'null'] format: date-time GlossaryTermInput: type: object required: [source_term] description: >- A whole term. On update, an optional field you omit is reset to its default, so send every field you want to keep. A `do_not_translate` or `forbidden` term carries no translations; any you send are dropped. properties: source_term: type: string maxLength: 255 example: Checkout part_of_speech: type: [string, 'null'] maxLength: 30 example: noun notes: type: [string, 'null'] maxLength: 2000 example: The page, not the verb. case_sensitive: type: boolean default: false do_not_translate: type: boolean default: false forbidden: type: boolean default: false translations: type: object description: Translations by locale. Empty values are ignored. additionalProperties: type: [string, 'null'] maxLength: 255 example: fr: Paiement de: Kasse GlossaryImportSummary: type: object properties: imported: type: integer description: '`created + updated`.' created: type: integer updated: type: integer unchanged: type: integer skipped: type: integer description: Rows that could not become a term, for example a row with no source term or a value over its length limit. wording_removed: type: integer description: Terms whose stored translations were removed because the file marks them forbidden or do not translate. wording_ignored: type: integer description: Terms the file gives translations for that were not used, because the term is forbidden or do not translate. no_source_column: type: boolean description: '`true` when a CSV header has no `source_term` column, so nothing was imported.' example: imported: 42 created: 30 updated: 12 unchanged: 7 skipped: 1 wording_removed: 0 wording_ignored: 0 no_source_column: false WebhookEventName: type: string enum: - batch.completed - batch.failed - key.created - key.updated - key.deleted - translation.updated - translation.reviewed - language.added - language.removed - glossary.updated - qa.completed - source_drift.repaired WebhookEndpoint: type: object properties: id: type: integer example: 7 url: type: string format: uri example: https://ci.example.com/hooks/transglot events: type: array items: $ref: '#/components/schemas/WebhookEventName' active: type: boolean description: Whether the endpoint receives deliveries. Paused endpoints miss events; nothing is sent later. created_at: type: [string, 'null'] format: date-time last_delivered_at: type: [string, 'null'] format: date-time description: When a delivery to this endpoint last succeeded. WebhookEndpointCreated: allOf: - $ref: '#/components/schemas/WebhookEndpoint' - type: object properties: secret: type: string description: >- The signing secret (`whsec_...`). It is returned in this response only and can never be read again. Use it to verify `X-Transglot-Signature`. example: whsec_Zq8mB3vN6xR1tY4uI7oP0aS2dF5gH8jK9lQ3wE6r WebhookEventEntry: type: object properties: event: $ref: '#/components/schemas/WebhookEventName' label: type: string example: Keys created description: type: string coalesced: type: boolean description: >- `true` when occurrences are counted over a window and delivered once, carrying `count` and up to 20 `samples`, instead of once per occurrence. window_seconds: type: integer description: The coalescing window; `0` for an event delivered once per occurrence. samples: type: string description: What the `samples` array contains, for example `key names`; empty for a discrete event. payload: type: object description: A representative payload. additionalProperties: true WebhookProjectRef: type: object properties: id: type: integer example: 12 slug: type: string example: acme-web WebhookEnvelope: type: object required: [event, delivered_at, project] properties: event: $ref: '#/components/schemas/WebhookEventName' delivered_at: type: string format: date-time description: When the event was emitted. A redelivery repeats the original value. project: $ref: '#/components/schemas/WebhookProjectRef' WebhookBatchPayload: allOf: - $ref: '#/components/schemas/WebhookEnvelope' - type: object properties: batch: $ref: '#/components/schemas/Batch' WebhookCoalescedPayload: allOf: - $ref: '#/components/schemas/WebhookEnvelope' - type: object properties: count: type: integer description: Occurrences in the window. samples: type: array maxItems: 20 description: Up to 20 examples, each at most 120 characters. items: type: string window_seconds: type: integer WebhookLanguageAddedPayload: allOf: - $ref: '#/components/schemas/WebhookEnvelope' - type: object properties: language: type: object properties: locale: type: string example: pt-BR WebhookLanguageRemovedPayload: allOf: - $ref: '#/components/schemas/WebhookEnvelope' - type: object properties: language: type: object properties: locale: type: string example: pt-BR translations_deleted: type: integer description: Translations deleted with the locale. example: 1204 responses: Unauthenticated: description: No token, an unknown, revoked or expired token. content: application/problem+json: schema: $ref: '#/components/schemas/Problem' example: type: /problems/unauthenticated title: Unauthenticated status: 401 detail: Unauthenticated. Forbidden: description: >- The token is valid but may not do this. `missing-ability`: the token lacks the ability this operation requires. `plan-feature-required`: the account's plan does not include API access. `ai-paused`, `workspace-read-only`, `workspace-closed`: the workspace's standing refuses this kind of request. content: application/problem+json: schema: $ref: '#/components/schemas/MissingAbilityProblem' examples: missing-ability: value: type: /problems/missing-ability title: Missing ability status: 403 detail: The token is missing a required ability. ability: manage plan-feature-required: value: type: /problems/plan-feature-required title: Plan feature required status: 403 detail: This project's account plan does not include API access. workspace-read-only: value: type: /problems/workspace-read-only title: Workspace read only status: 403 detail: This workspace is read-only right now. ForbiddenSpend: description: >- As `Forbidden`, plus the refusals of AI spend that a person has to lift: `ai-paused`, `free-account-held`, `email-verification-required`, and `plan-limit` when the operation needs a plan feature the account does not have. content: application/problem+json: schema: $ref: '#/components/schemas/Problem' examples: missing-ability: value: type: /problems/missing-ability title: Missing ability status: 403 detail: The token is missing a required ability. ability: manage ai-paused: value: type: /problems/ai-paused title: Ai paused status: 403 detail: AI translation is paused for this workspace. An account owner can see why in the Transglot console. email-verification-required: value: type: /problems/email-verification-required title: Email verification required status: 403 detail: AI translation starts when an owner of this account confirms their email address. PlanLimit: description: The account's plan does not include a feature this operation needs. content: application/problem+json: schema: $ref: '#/components/schemas/PlanLimitProblem' example: type: /problems/plan-limit title: Plan limit status: 403 detail: Quality mode is not included on Starter. Upgrade your plan to use this feature. resource: quality_mode cap: null upgrade_hint: Upgrade your plan to use this feature. NotFound: description: The resource does not exist in this project. content: application/problem+json: schema: $ref: '#/components/schemas/Problem' example: type: /problems/not-found title: Not found status: 404 detail: Not found. ValidationFailed: description: The request failed validation. content: application/problem+json: schema: $ref: '#/components/schemas/ValidationProblem' example: type: /problems/validation-failed title: Validation failed status: 422 detail: The request is invalid. errors: locale: - The locale field is required. RateLimited: description: Too many requests. Wait `Retry-After` seconds. headers: Retry-After: $ref: '#/components/headers/RetryAfter' X-RateLimit-Limit: $ref: '#/components/headers/RateLimitLimit' X-RateLimit-Remaining: $ref: '#/components/headers/RateLimitRemaining' X-RateLimit-Reset: $ref: '#/components/headers/RateLimitReset' content: application/problem+json: schema: $ref: '#/components/schemas/Problem' example: type: /problems/rate-limited title: Rate limited status: 429 detail: Too many requests. TooManyRequestsSpend: description: >- `rate-limited`: wait `Retry-After` seconds. `quota-exceeded`: the account has no AI words left for this cycle, or translation beyond the plan is paused; it lifts on its own at `quota.resets_at` when that is set. headers: Retry-After: description: Sent with `rate-limited` only. schema: type: integer content: application/problem+json: schema: $ref: '#/components/schemas/QuotaProblem' examples: rate-limited: value: type: /problems/rate-limited title: Rate limited status: 429 detail: Too many requests. quota-exceeded: value: type: /problems/quota-exceeded title: Quota exceeded status: 429 detail: The account this workspace belongs to has no AI words left for this cycle. They reset on 1 Nov 2026. quota: reason: plan_allowance scope: account requested: 4820 resets_at: '2026-11-01T00:00:00+00:00' LocaleNotConfigured: description: '`locale-not-configured`: the locale is not a language of this project, or `validation-failed`.' content: application/problem+json: schema: $ref: '#/components/schemas/ValidationProblem' examples: locale-not-configured: value: type: /problems/locale-not-configured title: Locale not configured status: 422 detail: Locale "pt-PT" is not configured on this project. validation-failed: value: type: /problems/validation-failed title: Validation failed status: 422 detail: The request is invalid. errors: locale: - The locale field is required. ActiveBatch: description: A translation batch is already running for this project. content: application/problem+json: schema: $ref: '#/components/schemas/ActiveBatchProblem' example: type: /problems/active-batch title: Active batch status: 409 detail: An AI translation batch is already running for this project. batch_id: 4820 GlossaryTermExists: description: '`glossary-term-exists`, or `validation-failed`.' content: application/problem+json: schema: $ref: '#/components/schemas/ValidationProblem' example: type: /problems/glossary-term-exists title: Glossary term exists status: 422 detail: A term with that source term already exists in this glossary. Update that term instead. CdnBundle: description: >- The bundle body in its published format; `Content-Type` follows the format, for example `application/json` for `json_flat`. headers: ETag: $ref: '#/components/headers/ETag' Cache-Control: description: '`public, max-age=60, must-revalidate` for the latest bundle; `public, max-age=31536000, immutable` for a version.' schema: type: string Access-Control-Allow-Origin: schema: type: string example: '*' X-Cdn-Version: description: The version served. schema: type: integer example: 14 X-Cdn-Format: description: The format the version was published in. schema: $ref: '#/components/schemas/FileFormat' content: application/json: schema: type: object additionalProperties: true example: checkout.submit: Payer maintenant checkout.error.declined: Votre carte a été refusée. CdnUnauthenticated: description: '`cdn-key-required` (no key sent) or `cdn-key-invalid` (unknown or revoked key).' content: application/problem+json: schema: $ref: '#/components/schemas/Problem' examples: cdn-key-required: value: type: /problems/cdn-key-required title: Cdn key required status: 401 detail: A CDN key is required (X-Transglot-Cdn-Key header or ?key=). cdn-key-invalid: value: type: /problems/cdn-key-invalid title: Cdn key invalid status: 401 detail: The CDN key is invalid or inactive. CdnForbidden: description: >- `plan-feature-required` when the account's plan no longer includes CDN delivery, or `workspace-closed`. Sent with `Cache-Control: no-store, private` so no cache keeps the refusal. content: application/problem+json: schema: $ref: '#/components/schemas/Problem' example: type: /problems/plan-feature-required title: Plan feature required status: 403 detail: This project's account plan does not include CDN delivery. CdnNotFound: description: >- `not-found` when the project id is not the key's project or the locale is not on the project; `not-published` when the locale, version or format has no published bundle. content: application/problem+json: schema: $ref: '#/components/schemas/Problem' examples: not-published: value: type: /problems/not-published title: Not published status: 404 detail: This locale has no published runtime bundle yet. not-found: value: type: /problems/not-found title: Not found status: 404 detail: Not found. CdnInvalidFormat: description: '`invalid-format`: the `format` query parameter is not a known format.' content: application/problem+json: schema: $ref: '#/components/schemas/Problem' example: type: /problems/invalid-format title: Invalid format status: 422 detail: Unknown format "jsn". paths: /v1/project: get: tags: [Project] operationId: getProject summary: Get the project description: >- The project the token belongs to: its name, source locale, every language with its progress, the key count and whether pushes translate on arrival. Accepts a token with any of `push`, `pull` or `manage`. x-required-ability: push | pull | manage responses: '200': description: The project. content: application/json: schema: $ref: '#/components/schemas/Project' example: id: 12 name: Acme Web slug: acme-web source_locale: en locales: - locale: de name: German rtl: false is_source: false progress: total: 1204 reviewed: 310 human: 42 ai: 820 empty: 32 translated: 1172 humanBacked: 352 percent: 97 - locale: en name: English rtl: false is_source: true progress: null keys_count: 1204 message_syntax: auto icu_dialect: icu4c auto_translate: true first_run_pending: false '401': $ref: '#/components/responses/Unauthenticated' '403': $ref: '#/components/responses/Forbidden' '429': $ref: '#/components/responses/RateLimited' /v1/push: post: tags: [Push and pull] operationId: push summary: Push a locale file description: >- Upload one locale file. A push of the source locale creates keys and updates source strings; a push of a target locale writes translations into existing keys and never creates keys. A translation you have edited or reviewed is never overwritten: a target value that would replace one is reported in `conflicts` with reason `human-edited`. A push never adds a language; push only locales the project already has. When automatic translation is on, a source push that changes strings starts a translation run, returned in `batch`. If the run cannot start, the push still applies and `quota_exceeded` or `translation_paused` says why. Push has its own rate limit of 300 requests per minute per token, separate from the general limit, because a repository upload is one request per file. x-required-ability: push requestBody: required: true content: multipart/form-data: schema: type: object required: [file, format, locale] properties: file: type: string format: binary description: The locale file, at most 10 MB. format: $ref: '#/components/schemas/FileFormat' locale: type: string maxLength: 35 description: The locale the file is in. It must already be configured on the project. example: en mode: type: string enum: [merge, sync_removals] default: merge description: >- `merge` adds and updates. `sync_removals` also deletes keys that are not in the file; it is allowed only when pushing the source locale. metadata: type: string format: binary description: >- Optional JSON sidecar of key descriptions and length limits, at most 1 MiB, sent as a file part. Only on a source push, and only for formats that cannot carry descriptions themselves (for example `json_flat` and `json_nested`). Shape: an object keyed by key name, each value an object with optional `description` (string or `null`) and `max_length` (integer or `null`). An absent field leaves the stored value alone; `null` clears it. hold: type: boolean description: >- Upload now and hold the project's first translation run until it is confirmed. Has no effect once the project's first run has been decided. import: type: string enum: [repo] description: >- `repo` brings existing translations from a repository into keys the source push created. Only with a target-locale push. encoding: file: contentType: application/octet-stream metadata: contentType: application/json responses: '200': description: The push was applied. content: application/json: schema: $ref: '#/components/schemas/PushResult' example: keys_created: 14 keys_deleted: 0 source_updated: 3 translations_written: 0 conflicts: [] unknown_keys: [] warnings: [] batch: id: 4822 status: processing trigger: push total: 34 completed: 0 failed: 0 skipped: 0 skipped_reasons: null tm_served: 0 language_breakdown: fr: 17 de: 17 started_at: '2026-10-12T09:50:01+00:00' finished_at: null quota_exceeded: false translation_paused: null '401': $ref: '#/components/responses/Unauthenticated' '403': $ref: '#/components/responses/Forbidden' '422': description: >- `locale-not-configured`, `sync-removals-requires-source`, `import-requires-target`, `metadata-requires-source`, `metadata-format-unsupported`, `metadata-invalid`, or `validation-failed` (including a file that does not parse in the given format, under `errors.file`). content: application/problem+json: schema: $ref: '#/components/schemas/ValidationProblem' examples: locale-not-configured: value: type: /problems/locale-not-configured title: Locale not configured status: 422 detail: Locale "pt-PT" is not configured on this project. Push never adds locales. sync-removals-requires-source: value: type: /problems/sync-removals-requires-source title: Sync removals requires source status: 422 detail: sync_removals is only allowed when pushing the source locale; deleting keys from a target file is never legal. metadata-invalid: value: type: /problems/metadata-invalid title: Metadata invalid status: 422 detail: The metadata sidecar is not valid. errors: - path: checkout.submit code: entry-not-an-object message: A sidecar entry is an object with description and/or max_length. error_count: 1 '429': $ref: '#/components/responses/RateLimited' /v1/pull: get: tags: [Push and pull] operationId: pull summary: Pull a locale as a file description: >- Download one locale in a file format. The body is the file itself, not JSON. An empty locale is served as a valid empty file, so read `X-Entry-Count` before you overwrite a file on disk. Send the `ETag` back as `If-None-Match` to get `304` when nothing changed; the count headers are sent on the `304` too. x-required-ability: pull parameters: - name: format in: query required: true schema: $ref: '#/components/schemas/FileFormat' - name: locale in: query required: true schema: type: string maxLength: 35 example: fr - name: min_state in: query required: false description: >- Leave out values below this state. `human_edited` keeps edited and reviewed values and leaves out Glossa drafts; `reviewed` keeps only approved values. Omit to include everything. schema: type: string enum: [human_edited, reviewed] - $ref: '#/components/parameters/IfNoneMatch' responses: '200': description: The file. `Content-Type` follows the format, for example `application/json` for `json_flat`. headers: ETag: $ref: '#/components/headers/ETag' Content-Disposition: description: 'An attachment filename, for example `attachment; filename="fr.json"`.' schema: type: string X-Entry-Count: description: Entries in this file. `0` means the file is empty. schema: type: integer X-Skipped-Keys: description: >- Keys left out because the format cannot carry them, for example plural keys in a format without plurals. schema: type: integer X-Missing-Source-Keys: description: >- In a bilingual format (`xliff_12`, `xliff_20`, `gettext_po`, `unreal_po`) pulled for a target locale, entries whose source slot is empty because the source has no value. For `gettext_po`, only plural entries are counted. schema: type: integer X-Omitted-Empty-Keys: description: Keys left out because their value in this locale is empty. schema: type: integer X-Omitted-Invalid-Icu-Keys: description: >- Translations left out because their message syntax would fail at runtime. Only non-zero on a project that uses ICU message syntax, and never in a bilingual format. schema: type: integer X-Omitted-Invalid-Icu-Sample: description: A JSON array of up to ten of those key names. `[]` when none. schema: type: string example: '["checkout.items_count"]' content: application/octet-stream: schema: type: string format: binary example: '{"checkout.submit":"Payer maintenant"}' '304': description: Not modified. The same headers as `200`, with no body. '401': $ref: '#/components/responses/Unauthenticated' '403': $ref: '#/components/responses/Forbidden' '422': description: >- `locale-not-configured`; `nested-key-collision` (a nested format cannot hold both `a` and `a.b`; the extension `keys` names them); `format-cannot-serialize` (the format cannot carry this project's keys; the extension `format` names it); or `validation-failed`. content: application/problem+json: schema: $ref: '#/components/schemas/NestedKeyCollisionProblem' examples: nested-key-collision: value: type: /problems/nested-key-collision title: Nested key collision status: 422 detail: "Keys cannot nest unambiguously: checkout, checkout.submit" keys: [checkout, checkout.submit] '429': $ref: '#/components/responses/RateLimited' /v1/translate: post: tags: [Translation] operationId: translate summary: Start a translation run description: >- Start a Glossa translation run over the project's pending strings. Answers `202` with the batch; poll `GET /v1/batches/{batch}` until its status is final. One batch per project runs at a time: while one is active this answers `409 active-batch` with its id. When nothing is pending, the batch comes back already `completed` with `total` 0. A translation you have edited or reviewed is never overwritten by AI; such pairs are counted in `skipped`. x-required-ability: manage requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/TranslateRequest' examples: missing: summary: Everything missing, in two languages value: scope: missing locales: [fr, de] selected: summary: Two keys value: scope: selected key_ids: [9132, 9133] responses: '202': description: The run was accepted. content: application/json: schema: $ref: '#/components/schemas/Batch' '401': $ref: '#/components/responses/Unauthenticated' '403': $ref: '#/components/responses/ForbiddenSpend' '409': $ref: '#/components/responses/ActiveBatch' '422': $ref: '#/components/responses/ValidationFailed' '429': $ref: '#/components/responses/TooManyRequestsSpend' /v1/batches: get: tags: [Batches] operationId: listBatches summary: List batches description: >- The project's 50 most recent batches, newest first. The body is a JSON array. Accepts a token with any of `push`, `pull` or `manage`. x-required-ability: push | pull | manage parameters: - name: status in: query required: false description: '`active` returns only `pending` and `processing` batches.' schema: type: string enum: [active] responses: '200': description: The batches. content: application/json: schema: type: array items: $ref: '#/components/schemas/Batch' '401': $ref: '#/components/responses/Unauthenticated' '403': $ref: '#/components/responses/Forbidden' '422': $ref: '#/components/responses/ValidationFailed' '429': $ref: '#/components/responses/RateLimited' /v1/batches/{batch}: get: tags: [Batches] operationId: getBatch summary: Get a batch description: >- One batch. With `include=failures`, the response adds `failures`, the failed pairs with their last error, at most 100. A batch of another project answers `404`. Accepts a token with any of `push`, `pull` or `manage`. x-required-ability: push | pull | manage parameters: - $ref: '#/components/parameters/BatchId' - name: include in: query required: false schema: type: string enum: [failures] responses: '200': description: The batch. content: application/json: schema: $ref: '#/components/schemas/BatchWithFailures' '401': $ref: '#/components/responses/Unauthenticated' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '422': $ref: '#/components/responses/ValidationFailed' '429': $ref: '#/components/responses/RateLimited' /v1/batches/{batch}/retry-failed: post: tags: [Batches] operationId: retryFailedBatch summary: Retry a batch's failed pairs description: >- Start a new batch over the failed pairs of this one. Answers `202` with the new batch, whose `trigger` is `retry_failed`. Refused with `409 active-batch` while another batch is running. x-required-ability: manage parameters: - $ref: '#/components/parameters/BatchId' responses: '202': description: The retry batch. content: application/json: schema: $ref: '#/components/schemas/Batch' '401': $ref: '#/components/responses/Unauthenticated' '403': $ref: '#/components/responses/ForbiddenSpend' '404': $ref: '#/components/responses/NotFound' '409': $ref: '#/components/responses/ActiveBatch' '429': $ref: '#/components/responses/TooManyRequestsSpend' /v1/batches/{batch}/cancel: post: tags: [Batches] operationId: cancelBatch summary: Cancel a batch description: >- Stop a running batch. Idempotent: a batch that has already finished answers `200` with its real status rather than an error, so read `status`. Cancel has its own rate limit of 60 requests per minute per token, separate from the general limit, so polling a batch never uses up the budget you need to stop it. x-required-ability: manage parameters: - $ref: '#/components/parameters/BatchId' responses: '200': description: The batch as it stands after the cancel. content: application/json: schema: $ref: '#/components/schemas/Batch' example: id: 4821 status: cancelled trigger: manual_missing total: 240 completed: 96 failed: 0 skipped: 0 skipped_reasons: null tm_served: 37 language_breakdown: fr: 120 de: 120 started_at: '2026-10-12T09:39:13+00:00' finished_at: '2026-10-12T09:40:02+00:00' '401': $ref: '#/components/responses/Unauthenticated' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/RateLimited' /v1/translations: get: tags: [Translations (single values)] operationId: getTranslation summary: Read one translation description: >- One key's source value and its value in `locale`, by key name. Requesting the source locale returns the source in both cells. x-required-ability: read parameters: - name: key in: query required: true schema: type: string maxLength: 500 example: checkout.submit - name: locale in: query required: true schema: type: string maxLength: 35 example: fr responses: '200': description: The row. content: application/json: schema: type: object properties: row: $ref: '#/components/schemas/TranslationRow' '401': $ref: '#/components/responses/Unauthenticated' '403': $ref: '#/components/responses/Forbidden' '404': description: No key with that name in this project. content: application/problem+json: schema: $ref: '#/components/schemas/Problem' '422': $ref: '#/components/responses/LocaleNotConfigured' '429': $ref: '#/components/responses/RateLimited' put: tags: [Translations (single values)] operationId: putTranslation summary: Write one translation description: >- Write a value for one key in one locale. The value is stored as `human_edited`, so no translation run overwrites it afterwards. Writing the source locale with a changed value queues a translation run for that key's target locales when automatic translation is on; if AI spend is refused, the write still succeeds. Send `expected_hash` to make the write conditional. If the value changed since you read it, the answer is `409` with the current row, and nothing is written. x-required-ability: write requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/TranslationWrite' examples: simple: summary: A simple key value: key: checkout.submit locale: fr content: Payer maintenant expected_hash: 3b5c0f6e1d7a9c2e4f8b0a6d2c4e6f8a1b3d5f7a9c1e3b5d7f9a2c4e6b8d0f1a plural: summary: A plural key value: key: cart.items locale: fr plural_forms: one: '{count} article' other: '{count} articles' responses: '200': description: The row as it stands after the write. content: application/json: schema: type: object properties: row: $ref: '#/components/schemas/TranslationRow' '401': $ref: '#/components/responses/Unauthenticated' '403': $ref: '#/components/responses/Forbidden' '404': description: No key with that name in this project. content: application/problem+json: schema: $ref: '#/components/schemas/Problem' '409': description: '`expected_hash` no longer matches. The body is the current row, not a problem document.' content: application/json: schema: $ref: '#/components/schemas/RowConflict' '422': description: >- `locale-not-configured`, or `validation-failed`, for example a write that omits `content`. content: application/problem+json: schema: $ref: '#/components/schemas/ValidationProblem' example: type: /problems/validation-failed title: Validation failed status: 422 detail: The request is invalid. errors: content: - A write must name content, even if it is empty. Omitting the field would blank the translation. '429': $ref: '#/components/responses/RateLimited' /v1/translations/batch: post: tags: [Translations (single values)] operationId: readTranslations summary: Read many translations description: >- Read up to 1,000 keys in one locale in one request. It is a `POST` only so the key names fit in a body; it changes nothing. Names that do not exist in the project are left out of `rows`, and a locale the project does not have returns no rows rather than an error. x-required-ability: read requestBody: required: true content: application/json: schema: type: object required: [locale, keys] properties: locale: type: string maxLength: 35 keys: type: array minItems: 1 maxItems: 1000 items: type: string maxLength: 500 example: locale: fr keys: [checkout.submit, checkout.error.declined] responses: '200': description: The rows found. content: application/json: schema: type: object properties: rows: type: array items: $ref: '#/components/schemas/TranslationRow' '401': $ref: '#/components/responses/Unauthenticated' '403': $ref: '#/components/responses/Forbidden' '422': $ref: '#/components/responses/ValidationFailed' '429': $ref: '#/components/responses/RateLimited' /v1/qa/run: post: tags: [Quality] operationId: runQualityCheck summary: Start a quality check description: >- Check translated strings with Glossa. Answers `202` with how much was queued; findings land on the translations, readable through `GET /v1/translations`, and the `qa.completed` webhook fires when the check finishes. Needs the Team plan or higher; otherwise `403 plan-limit`. x-required-ability: manage requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/QaRunRequest' example: scope: stale locales: [de] responses: '202': description: The check was queued. content: application/json: schema: $ref: '#/components/schemas/QaRunHandle' '401': $ref: '#/components/responses/Unauthenticated' '403': $ref: '#/components/responses/PlanLimit' '422': $ref: '#/components/responses/ValidationFailed' '429': $ref: '#/components/responses/TooManyRequestsSpend' /v1/cdn/publish: post: tags: [CDN] operationId: publishLocale summary: Publish a locale to the CDN description: >- Publish the locale's current translations as a new immutable bundle version, the API twin of the console's publish button. When the content is identical to the live version, no new version is minted and `created` is `false`. The bundle's format is the project's runtime delivery format. Needs a plan that includes CDN delivery; otherwise `403 plan-limit`. x-required-ability: manage requestBody: required: true content: application/json: schema: type: object required: [locale] properties: locale: type: string maxLength: 35 example: locale: fr responses: '200': description: The live bundle for this locale. content: application/json: schema: $ref: '#/components/schemas/CdnPublishResult' '401': $ref: '#/components/responses/Unauthenticated' '403': $ref: '#/components/responses/PlanLimit' '422': description: '`locale-not-configured`, `nested-key-collision` or `validation-failed`.' content: application/problem+json: schema: $ref: '#/components/schemas/NestedKeyCollisionProblem' '429': $ref: '#/components/responses/RateLimited' /v1/cdn/{project}/{locale}: get: tags: [CDN] operationId: getLatestBundle summary: Read the latest published bundle description: >- The newest published bundle for a locale. Authenticated with a CDN key, not a deploy token. Responses carry `Cache-Control: public, max-age=60, must-revalidate`, an `ETag` and `Access-Control-Allow-Origin: *`, so a browser, an app or an edge cache can fetch it directly. Rate limited to 300 requests per minute per key and client address. security: - cdnKeyHeader: [] - cdnKeyQuery: [] parameters: - $ref: '#/components/parameters/CdnProject' - $ref: '#/components/parameters/CdnLocale' - $ref: '#/components/parameters/CdnFormat' - $ref: '#/components/parameters/IfNoneMatch' responses: '200': $ref: '#/components/responses/CdnBundle' '304': description: Not modified. '401': $ref: '#/components/responses/CdnUnauthenticated' '403': $ref: '#/components/responses/CdnForbidden' '404': $ref: '#/components/responses/CdnNotFound' '422': $ref: '#/components/responses/CdnInvalidFormat' '429': $ref: '#/components/responses/RateLimited' /v1/cdn/{project}/{locale}/v{version}: get: tags: [CDN] operationId: getBundleVersion summary: Read one published version description: >- One exact published version. Its body never changes, so it is served with `Cache-Control: public, max-age=31536000, immutable`. Only the 20 most recent versions of a locale are kept, so pin a recent one. Authenticated with a CDN key. security: - cdnKeyHeader: [] - cdnKeyQuery: [] parameters: - $ref: '#/components/parameters/CdnProject' - $ref: '#/components/parameters/CdnLocale' - name: version in: path required: true schema: type: integer example: 14 - $ref: '#/components/parameters/CdnFormat' - $ref: '#/components/parameters/IfNoneMatch' responses: '200': $ref: '#/components/responses/CdnBundle' '304': description: Not modified. '401': $ref: '#/components/responses/CdnUnauthenticated' '403': $ref: '#/components/responses/CdnForbidden' '404': $ref: '#/components/responses/CdnNotFound' '422': $ref: '#/components/responses/CdnInvalidFormat' '429': $ref: '#/components/responses/RateLimited' /v1/glossary: get: tags: [Glossary] operationId: listGlossaryTerms summary: List glossary terms description: >- Terms in the project's glossary, 100 per page, in id order. Follow `next_cursor` until it is `null`. Needs a plan that includes the glossary. x-required-ability: read parameters: - name: status in: query required: false schema: type: string enum: [active, pending, rejected] default: active - name: cursor in: query required: false description: The `next_cursor` from the previous page. Opaque. schema: type: string responses: '200': description: One page of terms. content: application/json: schema: type: object properties: data: type: array items: $ref: '#/components/schemas/GlossaryTerm' next_cursor: type: [string, 'null'] '401': $ref: '#/components/responses/Unauthenticated' '403': $ref: '#/components/responses/PlanLimit' '422': $ref: '#/components/responses/ValidationFailed' '429': $ref: '#/components/responses/RateLimited' post: tags: [Glossary] operationId: createGlossaryTerm summary: Create a glossary term description: >- Create an active term. If an active term with the same source already exists, the request is refused with `422 glossary-term-exists`; update that term instead. If a pending or rejected candidate holds the same source, it becomes this active term. x-required-ability: manage requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/GlossaryTermInput' example: source_term: Checkout part_of_speech: noun notes: The page, not the verb. case_sensitive: false translations: fr: Paiement de: Kasse responses: '201': description: The term. content: application/json: schema: $ref: '#/components/schemas/GlossaryTerm' '401': $ref: '#/components/responses/Unauthenticated' '403': $ref: '#/components/responses/PlanLimit' '422': $ref: '#/components/responses/GlossaryTermExists' '429': $ref: '#/components/responses/RateLimited' /v1/glossary/{termId}: put: tags: [Glossary] operationId: updateGlossaryTerm summary: Replace a glossary term description: >- Replace a term. This is a full replace: an optional field you omit is reset to its default. Refused with `422 glossary-term-exists` when the new source collides with another term. x-required-ability: manage parameters: - $ref: '#/components/parameters/TermId' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/GlossaryTermInput' responses: '200': description: The term. content: application/json: schema: $ref: '#/components/schemas/GlossaryTerm' '401': $ref: '#/components/responses/Unauthenticated' '403': $ref: '#/components/responses/PlanLimit' '404': $ref: '#/components/responses/NotFound' '422': $ref: '#/components/responses/GlossaryTermExists' '429': $ref: '#/components/responses/RateLimited' delete: tags: [Glossary] operationId: deleteGlossaryTerm summary: Delete a glossary term x-required-ability: manage parameters: - $ref: '#/components/parameters/TermId' responses: '204': description: Deleted. '401': $ref: '#/components/responses/Unauthenticated' '403': $ref: '#/components/responses/PlanLimit' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/RateLimited' /v1/glossary/export: get: tags: [Glossary] operationId: exportGlossary summary: Export the glossary description: Active terms as a CSV or TBX download, sorted by source term. x-required-ability: read parameters: - name: format in: query required: false schema: type: string enum: [csv, tbx] default: csv responses: '200': description: >- The file, as an attachment named `glossary-.csv` or `.tbx`. The CSV has the columns `source_term`, `part_of_speech`, `case_sensitive`, `do_not_translate`, `forbidden`, `notes`, then one column per locale. content: text/csv: schema: type: string application/x-tbx: schema: type: string '401': $ref: '#/components/responses/Unauthenticated' '403': $ref: '#/components/responses/PlanLimit' '422': $ref: '#/components/responses/ValidationFailed' '429': $ref: '#/components/responses/RateLimited' /v1/glossary/import: post: tags: [Glossary] operationId: importGlossary summary: Import a glossary file description: >- Merge a CSV or TBX file into the glossary. Send the file as the raw request body; the format is detected from the content (a body containing `- Ask Glossa to propose terms from the project's source strings. Each run looks only at source strings changed since the previous run. Candidates arrive as `pending` terms; list them with `GET /v1/glossary?status=pending`. Needs the Team plan or higher. Extractions are capped per cycle; past the cap the answer is `429 extract-cap-reached` with the date it resets. x-required-ability: manage responses: '202': description: The extraction was queued. content: application/json: schema: type: object properties: chunks: type: integer description: Groups of strings queued for extraction. candidates: type: integer description: Candidate terms sent for review. example: chunks: 4 candidates: 380 '401': $ref: '#/components/responses/Unauthenticated' '403': $ref: '#/components/responses/PlanLimit' '429': description: '`rate-limited`, `quota-exceeded` or `extract-cap-reached`.' content: application/problem+json: schema: $ref: '#/components/schemas/CapProblem' example: type: /problems/extract-cap-reached title: Extract cap reached status: 429 detail: This workspace has used its share of glossary extractions for this cycle. They reset on 1 Nov 2026. cap: kind: extract scope: workspace resets_at: '2026-11-01T00:00:00+00:00' /v1/webhooks: get: tags: [Webhooks] operationId: listWebhooks summary: List webhook endpoints description: >- The project's webhook endpoints, in creation order. Signing secrets are never returned here. Accepts a token with any of `push`, `pull` or `manage`. x-required-ability: push | pull | manage responses: '200': description: The endpoints. content: application/json: schema: type: object properties: data: type: array items: $ref: '#/components/schemas/WebhookEndpoint' example: data: - id: 7 url: https://ci.example.com/hooks/transglot events: [batch.completed, batch.failed] active: true created_at: '2026-10-01T08:12:44+00:00' last_delivered_at: '2026-10-12T09:41:02+00:00' '401': $ref: '#/components/responses/Unauthenticated' '403': $ref: '#/components/responses/Forbidden' '429': $ref: '#/components/responses/RateLimited' post: tags: [Webhooks] operationId: createWebhook summary: Create a webhook endpoint description: >- Subscribe an endpoint to one or more events. The response carries the signing secret, and this is the only time it is returned. Endpoints must be publicly reachable HTTPS URLs on port 443; private and internal addresses are refused with `422 webhook-url-not-allowed`. Needs a plan that includes webhooks; otherwise `403 plan-limit`. x-required-ability: manage requestBody: required: true content: application/json: schema: type: object required: [url, events] properties: url: type: string maxLength: 2048 format: uri events: type: array minItems: 1 items: $ref: '#/components/schemas/WebhookEventName' example: url: https://ci.example.com/hooks/transglot events: [batch.completed, batch.failed] responses: '201': description: The endpoint, with its signing secret. content: application/json: schema: $ref: '#/components/schemas/WebhookEndpointCreated' example: id: 8 url: https://ci.example.com/hooks/transglot events: [batch.completed, batch.failed] active: true created_at: '2026-10-12T10:02:19+00:00' last_delivered_at: null secret: whsec_Zq8mB3vN6xR1tY4uI7oP0aS2dF5gH8jK9lQ3wE6r '401': $ref: '#/components/responses/Unauthenticated' '403': $ref: '#/components/responses/PlanLimit' '422': description: '`webhook-url-not-allowed` or `validation-failed`.' content: application/problem+json: schema: $ref: '#/components/schemas/ValidationProblem' examples: webhook-url-not-allowed: value: type: /problems/webhook-url-not-allowed title: Webhook url not allowed status: 422 detail: The webhook URL resolves to a private or reserved address. '429': $ref: '#/components/responses/RateLimited' /v1/webhooks/{webhook}: delete: tags: [Webhooks] operationId: deleteWebhook summary: Delete a webhook endpoint description: Delete the endpoint and its delivery log. An endpoint of another project answers `404`. x-required-ability: manage parameters: - $ref: '#/components/parameters/WebhookId' responses: '204': description: Deleted. '401': $ref: '#/components/responses/Unauthenticated' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/RateLimited' /v1/webhooks/events: get: tags: [Webhooks] operationId: listWebhookEvents summary: List webhook events description: >- Every event you can subscribe to, with whether it is coalesced, its window and a representative payload. Accepts a token with any of `push`, `pull` or `manage`. x-required-ability: push | pull | manage responses: '200': description: The event catalog. content: application/json: schema: type: object properties: data: type: array items: $ref: '#/components/schemas/WebhookEventEntry' '401': $ref: '#/components/responses/Unauthenticated' '403': $ref: '#/components/responses/Forbidden' '429': $ref: '#/components/responses/RateLimited' /v1/webhooks/events/{event}/sample: get: tags: [Webhooks] operationId: getWebhookEventSample summary: Get one event's catalog entry description: One event's catalog entry, including its representative payload. x-required-ability: push | pull | manage parameters: - name: event in: path required: true schema: $ref: '#/components/schemas/WebhookEventName' responses: '200': description: The catalog entry. content: application/json: schema: $ref: '#/components/schemas/WebhookEventEntry' example: event: key.created label: Keys created description: One or more translation keys were created (web CRUD or an API source push). coalesced: true window_seconds: 30 samples: key names payload: event: key.created delivered_at: '2026-07-08T09:41:00+00:00' project: id: 12 slug: acme-web count: 37 samples: [checkout.submit, checkout.error.declined] window_seconds: 30 '401': $ref: '#/components/responses/Unauthenticated' '403': $ref: '#/components/responses/Forbidden' '404': description: Unknown event. content: application/problem+json: schema: $ref: '#/components/schemas/Problem' example: type: /problems/not-found title: Not found status: 404 detail: Not found. '429': $ref: '#/components/responses/RateLimited' webhooks: batch.completed: post: tags: [Webhooks] operationId: webhook_batch_completed summary: batch.completed description: >- A translation batch finished: status `completed` or `completed_with_errors`. Delivered once per batch. parameters: - name: X-Transglot-Event in: header required: true description: The event name, repeated from the body. schema: $ref: '#/components/schemas/WebhookEventName' - name: X-Transglot-Delivery in: header required: true description: A UUID for this delivery. A redelivery gets a new one. schema: type: string format: uuid - name: X-Transglot-Timestamp in: header required: true description: Unix time, in seconds, when this attempt was signed. schema: type: string example: '1791820860' - name: X-Transglot-Signature in: header required: true description: >- `sha256=` followed by the lowercase hex HMAC-SHA256 of `.`, keyed with the endpoint's signing secret. schema: type: string example: sha256=5d1c3e8f0a2b4c6d8e0f1a3b5c7d9e1f3a5b7c9d1e3f5a7b9c1d3e5f7a9b1c3d - name: User-Agent in: header required: true schema: type: string example: transglot-webhooks/1 responses: '200': description: >- Any 2xx status marks the delivery as succeeded. Anything else, a timeout after 10 seconds or a redirect counts as a failure and is retried. requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/WebhookBatchPayload' example: event: batch.completed delivered_at: '2026-10-12T09:41:00+00:00' project: id: 12 slug: acme-web batch: id: 4821 status: completed trigger: push total: 240 completed: 240 failed: 0 skipped: 12 skipped_reasons: human_value_stale: 12 tm_served: 37 language_breakdown: fr: 120 de: 120 started_at: '2026-10-12T09:39:13+00:00' finished_at: '2026-10-12T09:41:00+00:00' batch.failed: post: tags: [Webhooks] operationId: webhook_batch_failed summary: batch.failed description: >- A translation batch ended with status `failed` or `cancelled`. Delivered once per batch. parameters: - name: X-Transglot-Event in: header required: true description: The event name, repeated from the body. schema: $ref: '#/components/schemas/WebhookEventName' - name: X-Transglot-Delivery in: header required: true description: A UUID for this delivery. A redelivery gets a new one. schema: type: string format: uuid - name: X-Transglot-Timestamp in: header required: true description: Unix time, in seconds, when this attempt was signed. schema: type: string example: '1791820860' - name: X-Transglot-Signature in: header required: true description: >- `sha256=` followed by the lowercase hex HMAC-SHA256 of `.`, keyed with the endpoint's signing secret. schema: type: string example: sha256=5d1c3e8f0a2b4c6d8e0f1a3b5c7d9e1f3a5b7c9d1e3f5a7b9c1d3e5f7a9b1c3d - name: User-Agent in: header required: true schema: type: string example: transglot-webhooks/1 responses: '200': description: >- Any 2xx status marks the delivery as succeeded. Anything else, a timeout after 10 seconds or a redirect counts as a failure and is retried. requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/WebhookBatchPayload' key.created: post: tags: [Webhooks] operationId: webhook_key_created summary: key.created description: >- Keys were created in the console or by a source push. Coalesced over 30 seconds; `samples` holds key names. parameters: - name: X-Transglot-Event in: header required: true description: The event name, repeated from the body. schema: $ref: '#/components/schemas/WebhookEventName' - name: X-Transglot-Delivery in: header required: true description: A UUID for this delivery. A redelivery gets a new one. schema: type: string format: uuid - name: X-Transglot-Timestamp in: header required: true description: Unix time, in seconds, when this attempt was signed. schema: type: string example: '1791820860' - name: X-Transglot-Signature in: header required: true description: >- `sha256=` followed by the lowercase hex HMAC-SHA256 of `.`, keyed with the endpoint's signing secret. schema: type: string example: sha256=5d1c3e8f0a2b4c6d8e0f1a3b5c7d9e1f3a5b7c9d1e3f5a7b9c1d3e5f7a9b1c3d - name: User-Agent in: header required: true schema: type: string example: transglot-webhooks/1 responses: '200': description: >- Any 2xx status marks the delivery as succeeded. Anything else, a timeout after 10 seconds or a redirect counts as a failure and is retried. requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/WebhookCoalescedPayload' key.updated: post: tags: [Webhooks] operationId: webhook_key_updated summary: key.updated description: >- Keys changed name, description, plural flag or length limit. Coalesced over 30 seconds; `samples` holds key names. parameters: - name: X-Transglot-Event in: header required: true description: The event name, repeated from the body. schema: $ref: '#/components/schemas/WebhookEventName' - name: X-Transglot-Delivery in: header required: true description: A UUID for this delivery. A redelivery gets a new one. schema: type: string format: uuid - name: X-Transglot-Timestamp in: header required: true description: Unix time, in seconds, when this attempt was signed. schema: type: string example: '1791820860' - name: X-Transglot-Signature in: header required: true description: >- `sha256=` followed by the lowercase hex HMAC-SHA256 of `.`, keyed with the endpoint's signing secret. schema: type: string example: sha256=5d1c3e8f0a2b4c6d8e0f1a3b5c7d9e1f3a5b7c9d1e3f5a7b9c1d3e5f7a9b1c3d - name: User-Agent in: header required: true schema: type: string example: transglot-webhooks/1 responses: '200': description: >- Any 2xx status marks the delivery as succeeded. Anything else, a timeout after 10 seconds or a redirect counts as a failure and is retried. requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/WebhookCoalescedPayload' key.deleted: post: tags: [Webhooks] operationId: webhook_key_deleted summary: key.deleted description: >- Keys were deleted in the console or by a push with `sync_removals`. Coalesced over 30 seconds; `samples` holds key names. parameters: - name: X-Transglot-Event in: header required: true description: The event name, repeated from the body. schema: $ref: '#/components/schemas/WebhookEventName' - name: X-Transglot-Delivery in: header required: true description: A UUID for this delivery. A redelivery gets a new one. schema: type: string format: uuid - name: X-Transglot-Timestamp in: header required: true description: Unix time, in seconds, when this attempt was signed. schema: type: string example: '1791820860' - name: X-Transglot-Signature in: header required: true description: >- `sha256=` followed by the lowercase hex HMAC-SHA256 of `.`, keyed with the endpoint's signing secret. schema: type: string example: sha256=5d1c3e8f0a2b4c6d8e0f1a3b5c7d9e1f3a5b7c9d1e3f5a7b9c1d3e5f7a9b1c3d - name: User-Agent in: header required: true schema: type: string example: transglot-webhooks/1 responses: '200': description: >- Any 2xx status marks the delivery as succeeded. Anything else, a timeout after 10 seconds or a redirect counts as a failure and is retried. requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/WebhookCoalescedPayload' translation.updated: post: tags: [Webhooks] operationId: webhook_translation_updated summary: translation.updated description: >- Translation values were written by a person, a push or a translation run. Coalesced over 15 seconds; `samples` holds `key:locale` pairs. parameters: - name: X-Transglot-Event in: header required: true description: The event name, repeated from the body. schema: $ref: '#/components/schemas/WebhookEventName' - name: X-Transglot-Delivery in: header required: true description: A UUID for this delivery. A redelivery gets a new one. schema: type: string format: uuid - name: X-Transglot-Timestamp in: header required: true description: Unix time, in seconds, when this attempt was signed. schema: type: string example: '1791820860' - name: X-Transglot-Signature in: header required: true description: >- `sha256=` followed by the lowercase hex HMAC-SHA256 of `.`, keyed with the endpoint's signing secret. schema: type: string example: sha256=5d1c3e8f0a2b4c6d8e0f1a3b5c7d9e1f3a5b7c9d1e3f5a7b9c1d3e5f7a9b1c3d - name: User-Agent in: header required: true schema: type: string example: transglot-webhooks/1 responses: '200': description: >- Any 2xx status marks the delivery as succeeded. Anything else, a timeout after 10 seconds or a redirect counts as a failure and is retried. requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/WebhookCoalescedPayload' translation.reviewed: post: tags: [Webhooks] operationId: webhook_translation_reviewed summary: translation.reviewed description: >- Translations were approved. Coalesced over 30 seconds; `samples` holds `key:locale` pairs. parameters: - name: X-Transglot-Event in: header required: true description: The event name, repeated from the body. schema: $ref: '#/components/schemas/WebhookEventName' - name: X-Transglot-Delivery in: header required: true description: A UUID for this delivery. A redelivery gets a new one. schema: type: string format: uuid - name: X-Transglot-Timestamp in: header required: true description: Unix time, in seconds, when this attempt was signed. schema: type: string example: '1791820860' - name: X-Transglot-Signature in: header required: true description: >- `sha256=` followed by the lowercase hex HMAC-SHA256 of `.`, keyed with the endpoint's signing secret. schema: type: string example: sha256=5d1c3e8f0a2b4c6d8e0f1a3b5c7d9e1f3a5b7c9d1e3f5a7b9c1d3e5f7a9b1c3d - name: User-Agent in: header required: true schema: type: string example: transglot-webhooks/1 responses: '200': description: >- Any 2xx status marks the delivery as succeeded. Anything else, a timeout after 10 seconds or a redirect counts as a failure and is retried. requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/WebhookCoalescedPayload' language.added: post: tags: [Webhooks] operationId: webhook_language_added summary: language.added description: >- A target language was added to the project. Delivered once. parameters: - name: X-Transglot-Event in: header required: true description: The event name, repeated from the body. schema: $ref: '#/components/schemas/WebhookEventName' - name: X-Transglot-Delivery in: header required: true description: A UUID for this delivery. A redelivery gets a new one. schema: type: string format: uuid - name: X-Transglot-Timestamp in: header required: true description: Unix time, in seconds, when this attempt was signed. schema: type: string example: '1791820860' - name: X-Transglot-Signature in: header required: true description: >- `sha256=` followed by the lowercase hex HMAC-SHA256 of `.`, keyed with the endpoint's signing secret. schema: type: string example: sha256=5d1c3e8f0a2b4c6d8e0f1a3b5c7d9e1f3a5b7c9d1e3f5a7b9c1d3e5f7a9b1c3d - name: User-Agent in: header required: true schema: type: string example: transglot-webhooks/1 responses: '200': description: >- Any 2xx status marks the delivery as succeeded. Anything else, a timeout after 10 seconds or a redirect counts as a failure and is retried. requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/WebhookLanguageAddedPayload' language.removed: post: tags: [Webhooks] operationId: webhook_language_removed summary: language.removed description: >- A target language was removed, with every translation in it. Delivered once. parameters: - name: X-Transglot-Event in: header required: true description: The event name, repeated from the body. schema: $ref: '#/components/schemas/WebhookEventName' - name: X-Transglot-Delivery in: header required: true description: A UUID for this delivery. A redelivery gets a new one. schema: type: string format: uuid - name: X-Transglot-Timestamp in: header required: true description: Unix time, in seconds, when this attempt was signed. schema: type: string example: '1791820860' - name: X-Transglot-Signature in: header required: true description: >- `sha256=` followed by the lowercase hex HMAC-SHA256 of `.`, keyed with the endpoint's signing secret. schema: type: string example: sha256=5d1c3e8f0a2b4c6d8e0f1a3b5c7d9e1f3a5b7c9d1e3f5a7b9c1d3e5f7a9b1c3d - name: User-Agent in: header required: true schema: type: string example: transglot-webhooks/1 responses: '200': description: >- Any 2xx status marks the delivery as succeeded. Anything else, a timeout after 10 seconds or a redirect counts as a failure and is retried. requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/WebhookLanguageRemovedPayload' glossary.updated: post: tags: [Webhooks] operationId: webhook_glossary_updated summary: glossary.updated description: >- Glossary terms were created, edited, approved, rejected, imported or deleted. Coalesced over 30 seconds; `samples` holds source terms. parameters: - name: X-Transglot-Event in: header required: true description: The event name, repeated from the body. schema: $ref: '#/components/schemas/WebhookEventName' - name: X-Transglot-Delivery in: header required: true description: A UUID for this delivery. A redelivery gets a new one. schema: type: string format: uuid - name: X-Transglot-Timestamp in: header required: true description: Unix time, in seconds, when this attempt was signed. schema: type: string example: '1791820860' - name: X-Transglot-Signature in: header required: true description: >- `sha256=` followed by the lowercase hex HMAC-SHA256 of `.`, keyed with the endpoint's signing secret. schema: type: string example: sha256=5d1c3e8f0a2b4c6d8e0f1a3b5c7d9e1f3a5b7c9d1e3f5a7b9c1d3e5f7a9b1c3d - name: User-Agent in: header required: true schema: type: string example: transglot-webhooks/1 responses: '200': description: >- Any 2xx status marks the delivery as succeeded. Anything else, a timeout after 10 seconds or a redirect counts as a failure and is retried. requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/WebhookCoalescedPayload' qa.completed: post: tags: [Webhooks] operationId: webhook_qa_completed summary: qa.completed description: >- A quality check finished scoring translations. Coalesced over 60 seconds; `samples` holds flagged `key:locale` pairs. parameters: - name: X-Transglot-Event in: header required: true description: The event name, repeated from the body. schema: $ref: '#/components/schemas/WebhookEventName' - name: X-Transglot-Delivery in: header required: true description: A UUID for this delivery. A redelivery gets a new one. schema: type: string format: uuid - name: X-Transglot-Timestamp in: header required: true description: Unix time, in seconds, when this attempt was signed. schema: type: string example: '1791820860' - name: X-Transglot-Signature in: header required: true description: >- `sha256=` followed by the lowercase hex HMAC-SHA256 of `.`, keyed with the endpoint's signing secret. schema: type: string example: sha256=5d1c3e8f0a2b4c6d8e0f1a3b5c7d9e1f3a5b7c9d1e3f5a7b9c1d3e5f7a9b1c3d - name: User-Agent in: header required: true schema: type: string example: transglot-webhooks/1 responses: '200': description: >- Any 2xx status marks the delivery as succeeded. Anything else, a timeout after 10 seconds or a redirect counts as a failure and is retried. requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/WebhookCoalescedPayload' source_drift.repaired: post: tags: [Webhooks] operationId: webhook_source_drift_repaired summary: source_drift.repaired description: >- Source strings changed and the affected translations were checked again and repaired or given a suggestion, following the project's source-drift setting. Coalesced over 60 seconds; `samples` holds flagged `key:locale` pairs. parameters: - name: X-Transglot-Event in: header required: true description: The event name, repeated from the body. schema: $ref: '#/components/schemas/WebhookEventName' - name: X-Transglot-Delivery in: header required: true description: A UUID for this delivery. A redelivery gets a new one. schema: type: string format: uuid - name: X-Transglot-Timestamp in: header required: true description: Unix time, in seconds, when this attempt was signed. schema: type: string example: '1791820860' - name: X-Transglot-Signature in: header required: true description: >- `sha256=` followed by the lowercase hex HMAC-SHA256 of `.`, keyed with the endpoint's signing secret. schema: type: string example: sha256=5d1c3e8f0a2b4c6d8e0f1a3b5c7d9e1f3a5b7c9d1e3f5a7b9c1d3e5f7a9b1c3d - name: User-Agent in: header required: true schema: type: string example: transglot-webhooks/1 responses: '200': description: >- Any 2xx status marks the delivery as succeeded. Anything else, a timeout after 10 seconds or a redirect counts as a failure and is retried. requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/WebhookCoalescedPayload'