Webhooks API
Webhooks let you receive real-time HTTP notifications when events happen in your Comvi projects. Instead of polling the API, you register a URL and Comvi sends a POST request to it whenever a subscribed event fires.
Events
Section titled “Events”Subscribe to any combination of these events:
| Event | Description |
|---|---|
translation.created | A translation value was added |
translation.updated | A translation value was changed |
translation.deleted | A translation value was removed |
translation.batch_updated | Multiple translations were updated at once |
key.created | A new translation key was created |
key.updated | A translation key was renamed or modified |
key.deleted | A translation key was deleted |
namespace.created | A new namespace was created |
namespace.updated | A namespace was renamed |
namespace.deleted | A namespace was deleted |
import.completed | A translation import finished processing |
export.completed | A translation export finished processing |
comment.created | A comment was added to a translation |
comment.resolved | A comment was resolved |
project.locale_added | A language was added to the project |
project.locale_removed | A language was removed from the project |
webhook.test | Sent when you trigger a test delivery |
webhook.disabled | The webhook was automatically disabled due to consecutive failures |
List webhooks
Section titled “List webhooks”Returns all webhooks configured for a project.
GET /api/v1/projects/:projectId/webhooksPath parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
projectId | integer | Yes | Project ID |
Example request
curl -X GET \ -H "X-API-Key: tlk_your_api_key" \ https://api.comvi.io/api/v1/projects/5/webhooksExample response
[ { "id": 1, "uuid": "wh_abc123", "organizationId": 1, "projectId": 5, "name": "Translation Updates", "url": "https://example.com/webhooks/comvi", "events": ["translation.created", "translation.updated"], "isActive": true, "consecutiveFailures": 0, "lastTriggeredAt": "2025-03-25T10:00:00Z", "lastSuccessAt": "2025-03-25T10:00:00Z", "createdBy": 42, "createdAt": "2025-01-15T08:00:00Z", "updatedAt": "2025-01-15T08:00:00Z" }]Create webhook
Section titled “Create webhook”Register a new webhook endpoint for a project. The response includes a secret that you use to verify webhook signatures.
POST /api/v1/projects/:projectId/webhooksPath parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
projectId | integer | Yes | Project ID |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Descriptive name (1-255 characters) |
url | string | Yes | HTTPS endpoint URL to receive events (up to 2048 characters) |
events | string[] | Yes | Event types to subscribe to (at least one) |
isActive | boolean | No | Whether the webhook is active (default: true) |
Example request
curl -X POST \ -H "X-API-Key: tlk_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "name": "Translation Sync", "url": "https://example.com/webhooks/comvi", "events": ["translation.created", "translation.updated", "translation.deleted"] }' \ https://api.comvi.io/api/v1/projects/5/webhooksExample response
{ "id": 2, "uuid": "wh_def456", "organizationId": 1, "projectId": 5, "name": "Translation Sync", "url": "https://example.com/webhooks/comvi", "events": ["translation.created", "translation.updated", "translation.deleted"], "isActive": true, "consecutiveFailures": 0, "lastTriggeredAt": null, "lastSuccessAt": null, "createdBy": 42, "createdAt": "2025-03-25T12:00:00Z", "updatedAt": "2025-03-25T12:00:00Z", "secret": "whsec_a1b2c3d4e5f6g7h8i9j0..."}Update webhook
Section titled “Update webhook”Update a webhook’s name, URL, subscribed events, or active status.
PATCH /api/v1/webhooks/:idPath parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | integer | Yes | Webhook ID |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
name | string | No | Updated name |
url | string | No | Updated endpoint URL |
events | string[] | No | Updated event subscriptions |
isActive | boolean | No | Enable or disable the webhook |
Example request
curl -X PATCH \ -H "X-API-Key: tlk_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "events": ["translation.created", "translation.updated", "translation.deleted", "key.created"], "isActive": true }' \ https://api.comvi.io/api/v1/webhooks/2Example response
{ "id": 2, "uuid": "wh_def456", "organizationId": 1, "projectId": 5, "name": "Translation Sync", "url": "https://example.com/webhooks/comvi", "events": ["translation.created", "translation.updated", "translation.deleted", "key.created"], "isActive": true, "consecutiveFailures": 0, "lastTriggeredAt": null, "lastSuccessAt": null, "createdBy": 42, "createdAt": "2025-03-25T12:00:00Z", "updatedAt": "2025-03-25T12:30:00Z"}Delete webhook
Section titled “Delete webhook”Permanently remove a webhook. No further events will be delivered to this endpoint.
DELETE /api/v1/webhooks/:idPath parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | integer | Yes | Webhook ID |
Example request
curl -X DELETE \ -H "X-API-Key: tlk_your_api_key" \ https://api.comvi.io/api/v1/webhooks/2Response
Returns 204 No Content on success.
Test webhook
Section titled “Test webhook”Send a test event to your webhook endpoint. This creates a real delivery with the webhook.test event type so you can verify your integration works.
POST /api/v1/webhooks/:id/testPath parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | integer | Yes | Webhook ID |
Example request
curl -X POST \ -H "X-API-Key: tlk_your_api_key" \ https://api.comvi.io/api/v1/webhooks/1/testExample response
{ "id": 100, "uuid": "del_abc123", "webhookId": 1, "event": "webhook.test", "payload": {}, "status": "success", "httpStatus": 200, "attemptNumber": 1, "responseBody": "OK", "errorMessage": null, "durationMs": 145, "sentAt": "2025-03-25T12:00:00Z", "completedAt": "2025-03-25T12:00:00Z", "nextRetryAt": null, "createdAt": "2025-03-25T12:00:00Z"}Verifying webhook signatures
Section titled “Verifying webhook signatures”Every webhook delivery includes a signature in the X-Webhook-Signature header. Verify it using your webhook secret to ensure the request came from Comvi.
import crypto from 'crypto';
function verifyWebhookSignature(payload, signature, secret) { const expected = crypto .createHmac('sha256', secret) .update(payload) .digest('hex');
return crypto.timingSafeEqual( Buffer.from(signature), Buffer.from(expected) );}
// In your webhook handler:app.post('/webhooks/comvi', (req, res) => { const signature = req.headers['x-webhook-signature']; const isValid = verifyWebhookSignature( JSON.stringify(req.body), signature, process.env.COMVI_WEBHOOK_SECRET );
if (!isValid) { return res.status(401).send('Invalid signature'); }
// Process the event const { event, data } = req.body; console.log(`Received ${event}:`, data);
res.status(200).send('OK');});Delivery and retries
Section titled “Delivery and retries”Comvi tracks every delivery attempt. If your endpoint returns a non-2xx status code, Comvi retries the delivery with exponential backoff:
| Attempt | Delay |
|---|---|
| 1st retry | ~1 minute |
| 2nd retry | ~5 minutes |
| 3rd retry | ~30 minutes |
After multiple consecutive failures, the webhook is automatically disabled and a webhook.disabled event is recorded. Re-enable it from the dashboard or via the Update webhook endpoint.
Errors
Section titled “Errors”| Status | Error Code | Description |
|---|---|---|
403 | FORBIDDEN | Missing webhook permission |
404 | WEBHOOK_NOT_FOUND | The specified webhook does not exist |
404 | WEBHOOK_DELIVERY_NOT_FOUND | The specified delivery does not exist |