TextMaster · AsyncAPI Specification
Textmaster Event Surface
Version
View Spec
View on GitHub
CompanyTranslationLocalizationLanguage ServicesCopywritingProofreadingMachine TranslationContent ProductionTranslation MemoryGlossaryEcommerce LocalizationProduct Information ManagementWebhookAuthenticationSoftware-as-a-ServiceAsyncAPIWebhooksEvents
AsyncAPI Specification
generated: '2026-08-17'
method: searched
source: >-
https://developer.textmaster.com/webhooks-and-events/events +
https://developer.textmaster.com/webhooks-and-events/webhooks +
https://developer.textmaster.com/webhooks-and-events/webhooks/creating-webhooks +
https://developer.textmaster.com/webhooks-and-events/webhooks/securing-webhooks +
https://developer.textmaster.com/webhooks-and-events/webhooks/troubleshooting-webhooks +
https://developer.textmaster.com/guides/integrator-best-practices +
openapi/textmaster-api-v1-openapi.yml
checked: '2026-08-17'
spec_type: none
summary: >-
TextMaster ships a real, customer-registerable webhook surface — 19 named events across Projects
and Documents, registered through the REST API itself, with a published retry budget, delivery
semantics, an event-type request header and a documented securing pattern. It publishes NO
AsyncAPI document. This artifact is therefore the webhook catalogue, and the apis.yml pointer is
`Webhooks`, not `AsyncAPI`.
asyncapi:
present: false
probed:
- url: https://api.textmaster.com/asyncapi.yaml
status: 404
checked: '2026-08-17'
- url: https://developer.textmaster.com/llms.txt
status: 200
checked: '2026-08-17'
finding: >-
The portal's complete 58-page index contains no AsyncAPI, event-catalog spec, or streaming
page. The event contract is prose + the callback objects inside the OpenAPI.
note: >-
No AsyncAPI is published anywhere. Not fabricated. No `AsyncAPI` pointer is emitted; the
asyncapi scoring family stays out of this provider's denominator on spec-shape checks while the
`Webhooks` signal is genuinely earned.
webhooks:
customer_registerable: true
registration_mechanism: >-
Webhooks are not a separate resource. They are registered as `callback` objects on the REST
write surface, at three levels of scope, each keyed by event name with a `{ "url": "..." }`
value.
registration_levels:
- level: user (global)
operation: PUT /v1/clients/users/{user_id}
scope_required: ['user:manage', 'user:write']
body_path: user.callback.<event>.url
events_available_in_spec: [waiting_assignment, completed]
note: >-
The spec models only two events at user level, but the creating-webhooks tutorial registers
`word_count_finished` here, so the spec's user-level callback map is narrower than the real
surface. Treat the documented event list as authoritative.
example: |
curl "https://api.textmaster.com/v1/clients/users/USER_ID" \
-X PUT \
-H "Authorization: Bearer ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"user":{"callback":{"word_count_finished":{"url":"https://example.com/payload"}}}}'
- level: project
operation: POST /v1/clients/projects (and PUT /v1/clients/projects/{project_id})
scope_required: ['project:manage', 'project:write']
body_path: project.callback.<event>.url
description_in_spec: List of callbacks to be called upon Project status changes.
- level: document
operation: >-
POST /v1/clients/projects/{project_id}/documents (and the batch create, and
PUT .../documents/{document_id})
scope_required: ['project:manage', 'project:write']
body_path: document.callback.<event>.url
description_in_spec: List of callbacks to be called upon Document status changes.
openapi_webhooks_block: false
openapi_callbacks_keyword: false
openapi_representation_note: >-
The OpenAPI does NOT use the 3.1 top-level `webhooks` object nor operation-level `callbacks`.
The event surface appears only as ordinary request/response schema properties named `callback`,
plus a `CallbackUrl` component ({url, format}). A code generator reading the spec will produce
a settable field, not a subscription API, and will not know the event names are an enum. This
is the single biggest machine-readability gap in TextMaster's contract, and the reason this
catalogue is worth writing down.
delivery:
method: POST
payload_format: JSON
event_type_header: X-TextMaster-Event
event_type_header_quote: >-
"The X-TextMaster-Event request header can be used to know which event has been received so
that processing can be handled appropriately."
ssl_verification: true
ssl_verification_quote: >-
"By default, TextMaster will verify SSL certificates when delivering payloads. Any SSL errors
will be logged in the webhook's response."
receiver_timeout_seconds: 30
retries: 20
retry_strategy: exponential backoff
delivery_guarantee: at-least-once
ordering_guarantee: none
ordering_quote: >-
"We also cannot guarantee the order in which webhooks are delivered. Your server should
handle receiving events out of order."
consumer_idempotency_required: true
consumer_idempotency_quote: >-
"Your server implementation should be idempotent, meaning it should not error out if
receiving the same webhook multiple times."
expected_response_codes: >-
Any prompt 2xx. The docs suggest 201 or 202 to acknowledge a payload that will not be
processed, and reserving 500 for catastrophic failures.
security:
signature_header: false
signature_header_note: >-
There is NO HMAC signature header today. TextMaster says so plainly and states an intent:
"In the future, TextMaster will use your secret token to create a hash signature of each
payload." Until then a receiver cannot cryptographically verify a delivery.
documented_pattern: shared-secret-in-callback-URL
documented_pattern_detail: >-
The integrator embeds a high-entropy token as a query parameter of the callback URL it
registers (e.g. https://example.com/payload?token=<40 hex chars>) and compares it on receipt.
The docs suggest generating it with `ruby -rsecurerandom -e 'puts SecureRandom.hex(20)'` and
recommend a DIFFERENT token per user of the integrator's service.
weakness_note: >-
A URL query parameter is a weaker channel than a signature header: it is logged by proxies
and web servers by default and it authenticates the endpoint, not the payload. Recorded as
published, not endorsed.
source_ip_allowlist:
recommended_by_provider: false
provider_caveat: >-
"Our public IP addresses are subject to changes, we do not encourage using IP addresses to
secure payload delivery."
production:
- 104.155.57.91
- 104.155.91.236
- 35.205.172.93
- 34.140.71.130
sandbox:
- 34.76.154.26
- 34.76.94.225
- 34.76.144.86
- 35.241.160.58
note: >-
Published verbatim in the integrator best-practices guide. Two disjoint egress ranges
confirm the sandbox is genuinely separate infrastructure, not a flag on production.
observability:
delivery_log: true
delivery_log_detail: >-
TextMaster exposes recent deliveries in the application with the full outbound HTTP request
(headers + JSON payload) and the receiver's response (status, headers, body). Failed
deliveries are visible per attempt.
retention: unquantified
event_count: 19
events:
- resource: project
name: project_in_progress
description: >-
Triggered when a project has launched and is made available to be claimed by an author.
reconciliation_note: >-
The recovery primitive for the missing idempotency key: "Launch process can safely be retried
if this event is not received in a reasonable time (more than 30 minutes)."
- resource: project
name: project_finalized
description: >-
Triggered when a project is finalized, meaning that all documents have been attached to it and
translation memory analysis and/or PEMT have been ran successfully.
- resource: project
name: project_not_launched
description: >-
Triggered when a project with the `auto_launch` option cannot be launched, often due to the
client account not having enough credits on its wallet.
commercial_note: The insufficient-funds event. Essential for any agent that launches projects.
- resource: project
name: project_canceled
description: Triggered when a project is canceled.
spelling_note: >-
Both `project_canceled` and `project_cancelled` appear as accepted callback keys in the
OpenAPI request schema. The events documentation uses the single-l `project_canceled`. A
receiver should tolerate both.
- resource: project
name: project_tm_completed
description: >-
Triggered when a project's translation memory analysis has successfully completed and the
project's cost has been updated accordingly.
commercial_note: Cost changes on this event; re-read the project before launching.
- resource: project
name: project_tm_diff_completed
description: >-
Triggered when a project's "Force Exact Matches" analysis has successfully completed and the
project's cost has been updated accordingly.
- resource: project
name: project_in_review
description: >-
Triggered when the work for all project's documents has been submitted, and the documents are
ready for internal quality control or for review by the client.
- resource: document
name: waiting_assignment
kind: status-change
description: Document is published and awaiting an author.
- resource: document
name: in_progress
kind: status-change
description: An author has claimed the document and work has begun.
- resource: document
name: in_review
kind: status-change
description: Work submitted and available for review.
- resource: document
name: incomplete
kind: status-change
- resource: document
name: completed
kind: status-change
description: Final content is available; retrieve it via the document's author_work URL.
- resource: document
name: paused
kind: status-change
- resource: document
name: canceled
kind: status-change
- resource: document
name: quality_control
kind: status-change
- resource: document
name: copyscape
kind: status-change
description: Plagiarism check stage (Copyscape is a named subprocessor).
- resource: document
name: counting_words
kind: status-change
- resource: document
name: word_count_finished
kind: task-completion
description: Triggered when the task of counting words on a document has successfully completed.
- resource: document
name: support_message_created
kind: activity
description: Triggered when a new message has been created on a document's support thread.
related_operations:
- GET /v1/clients/projects/{project_id}/documents/{document_id}/support_messages
- POST /v1/clients/projects/{project_id}/documents/{document_id}/support_messages
additional_callback_keys_in_spec:
note: >-
Three callback keys appear in the OpenAPI request schemas but are NOT in the documented event
tables. Recorded as observed, unconfirmed by docs.
keys:
- in_creation
- in_extra_review
- complete
caveat: >-
`complete` and `completed` both appear as document callback keys in the spec; only `completed`
is documented. Do not assume `complete` fires.
streaming:
present: false
note: No SSE, WebSocket or message-queue surface is documented or discoverable.
polling_alternative:
available: true
operations:
- GET /v1/clients/projects/{project_id}
- GET /v1/clients/projects/{project_id}/documents/{document_id}
- GET /v1/clients/projects/filter
provider_guidance: >-
Discouraged. "Always prefer using webhooks over HTTP polling for reliability." The stated
reason is payload size: fetching finished documents over the API risks the 30-second timeout,
whereas webhooks push the content to you.