Webhook events
Taia can send an HTTP request to a URL of your choice when something happens to a project or order. This lets you integrate Taia into your own systems without polling.
Webhooks belong to an API key, so you need a plan that includes API access.
Set up a webhook in the app
- Click your name at the bottom of the sidebar to open your Profile.
- On the Manage Your API Keys card, click Manage API Keys.
- On the row of the API key you want to use, click Webhooks. If you don't have a key yet, create one first.
- Click Create Webhook and fill in:
- Webhook URL: the HTTPS endpoint Taia should call.
- Description (optional).
- Events: one or more of the events below.
- Trigger Sources: API for projects and orders created through the API, Web UI for ones created on the website, or both.
- Click Create Webhook. Copy the Webhook Secret now: it's shown only once, and you need it to verify signatures.
On the same page you can open each webhook's delivery history and delete the webhook.
Set up a webhook through the API
You can also manage webhooks with the API key itself, using the Authorization: Api-Key <your key> header:
| Method | Path | What it does |
|---|---|---|
POST | /api/public/v1/webhooks | Create a webhook. Body: url (HTTPS), events (array), description (optional). The response contains the secret, shown only once. |
GET | /api/public/v1/webhooks | List the key's webhooks. |
GET | /api/public/v1/webhooks/{id} | Get one webhook. |
PATCH | /api/public/v1/webhooks/{id} | Change url, events, description or is_active. |
DELETE | /api/public/v1/webhooks/{id} | Delete a webhook. |
GET | /api/public/v1/webhooks/{id}/deliveries | Delivery history. |
POST | /api/public/v1/webhooks/{id}/deliveries/{delivery_id}/retry | Retry a delivery that hasn't used up its 5 attempts. |
Through the API, each key can have up to 5 webhooks and the URL must use HTTPS. The same URL can't be registered twice on one key. Webhooks created through the API receive events from both trigger sources.
The API also accepts a few event names that Taia doesn't send yet (project.created, order.submitted, order.assigned, order.in_progress, order.in_review). Subscribe only to the events in the table below.
Event types
| Event | Sent when |
|---|---|
project.converted | The project's files have been converted and are ready for analysis. |
project.analysis_completed | The word count analysis has finished. |
project.quote_ready | A quote for professional translation has been generated. |
project.mt_completed | AI translation has finished. |
project.failed | Processing failed. |
order.created | A professional translation order has been placed. |
order.delivered | The order has been delivered. |
order.cancelled | The order has been cancelled. |
Which webhooks receive an event:
- Projects created through the API send their events only to webhooks on the API key that created them.
- Projects created on the website send their events to webhooks on the owner's API keys and on the keys of the project's team.
- Order events are sent only for orders on projects created through the API, or orders placed through the API.
order.deliveredandorder.cancelledare sent when Taia's team updates the order, so they arrive whatever the webhook's Trigger Sources are.
order.created can be selected in the app but not yet through the API.
Payload format
Every webhook is a POST request with a JSON body:
{
"event": "project.mt_completed",
"timestamp": "2026-09-24T12:00:00+00:00",
"data": {
"project_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"project_name": "Product manual",
"status": "completed",
"source_language": "en-US",
"target_languages": ["de-DE", "fr-FR"],
"team_id": null,
"organization_id": null,
"updated_at": "2026-09-24T12:00:00+00:00",
"source": "api"
}
}
data always contains source (api or ui, or admin when Taia's team changed an order). Project events include project_id. Order events include order_id, project_id and status. The other fields depend on the event: project.analysis_completed adds the word counts per language, project.quote_ready adds the quote ID, currency and totals, and project.failed can add an error_message.
Headers
| Header | Value |
|---|---|
Content-Type | application/json |
User-Agent | Taia-Webhooks/1.0 |
X-Webhook-Event | The event name, e.g. project.mt_completed |
X-Webhook-Delivery-ID | A unique ID for this delivery. Use it to ignore duplicates. |
X-Webhook-Attempt | 1 for the first attempt, higher for retries |
X-Webhook-Signature | The signature (see below) |
Verify the signature
X-Webhook-Signature is the HMAC-SHA256 of the raw request body, keyed with your webhook secret, as a lowercase hex string. Compute it over the body bytes exactly as received, before parsing the JSON, and compare it with a constant-time comparison.
import hashlib, hmac
def is_from_taia(raw_body: bytes, signature: str, secret: str) -> bool:
expected = hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, signature)
Retries
Respond with any 2xx status within 30 seconds to acknowledge a delivery. Anything else, including a timeout, counts as a failure, and Taia tries again after 1 minute, 5 minutes, 30 minutes and 2 hours. After 5 failed attempts the delivery is permanently marked as failed and isn't sent again. Use GET /api/public/v1/projects/{id} or the app to catch up on what you missed.