Webhooks
Webhooks are a very common tool to keep different systems in sync. Use webhooks to receive instant notifications about events happening in Lokalise as HTTP POST requests.
To set up the Webhooks app for your project:
- Navigate to Apps.
- Find Webhooks in the list, click on it, and then press Install.
- Enter the configuration parameters: URL to send events to, and the branch (if the branching feature is enabled for your project).
- Configure the header, if you need to.
- Select the desired events.
- Click Enable app.
Alternatively, you can subscribe and unsubscribe from webhooks programmatically, using our API. Find more information and try out the API on our playground.
Requirements
The webhook is sent once an event happens and it expects a response from your endpoint, configured on the URL parameter.
- Your service must accept HTTP POST requests.
- Your service must return a
2xx
status code (200, 201, 202, etc.) upon receiving a notification, including the initialping
that is sent when a new webhook handler is configured.
You can check the Webhook sample apps to learn how to listen to webhook events in third-party apps, and handle the incoming notifications.
Origin IP addresses
We do not sign the requests, so you may want to restrict the incoming requests from the following IPs:
- 159.69.72.82
- 94.130.129.39
- 195.201.158.210
- 94.130.129.237
- 195.201.84.53
- 18.192.113.205
- 3.67.82.138
HTTP header
A special HTTP header is sent with every notification for security purposes. By checking the header's value, your service endpoint can validate that the request is coming from Lokalise and not a malicious source.
By default, a webhook secret is generated for you automatically once the app is enabled. The secret is represented as a random alphanumeric string and is sent inside an X-Secret
header. This secret can be regenerated at any time. To do that, open Apps > Webhooks, find the desired webhook and click on the Refresh icon:
You can also enter any other value for this header in the text input.
Moreover, you can also choose to send not an X-Secret
but an X-Api-Key
: in this case you'll need to provide a value for this header as well.
Finally you can choose to send a custom header by selecting the corresponding radio box:
In this case you'll need to enter the header's name (we recommend to use an X-
prefix) and its value.
Retry mechanism
In case a webhook handler failed to receive the notification, our system will try to re-send it up to 24 hours:
- after ± 1 minute, after the first failure.
- after ± 5 minutes, after the second failure.
- after ± 10 minutes, after the third failure.
- after ± 20 minutes, after the fourth failure.
- after ± 30 minutes, after the fifth failure.
- every hour up to 24 hours.
We do our best to preserve the order of webhooks, though it is not guaranteed. All events will continue to accumulate for up to 24 hours if the webhook handler is not responding.
After 24 hours all accumulated events will be deleted and the webhook handler disabled. A disabled webhook handler must be re-enabled manually in the project settings.
Please note that if your application fails to process the webhook notification in 8 seconds (in other words, it does not respond with a 2xx
status code), we'll consider the request to be unsuccessful and will try to re-send it as explained above.
Available webhook events
project.imported
— fires whenever translation files were uploaded to a project.project.exported
— fires whenever translation files were downloaded from a project.project.deleted
— fires when a project has been deleted.project.snapshot
— fires when a project snapshot was created.project.branch.added
— fires when a new project branch was created.project.branch.deleted
— fires when a project branch was deleted.project.branch.merged
— fires when two project branches were merged.project.languages.added
— fires when a new language was added to a project.project.language.removed
— fires when a language was removed from a project.project.language.settings_changed
— fires when language settings have been changed.project.key.added
— fires when a new translation key has been added to a project.project.keys.added
— fires when new translation keys have been added to a project through a bulk action. Each event will include up to a maximum of 300 keys in the payload.project.key.modified
— fires when a translation key has been modified in a project.project.keys.deleted
— fires when a translation key has been removed from a project.project.key.comment.added
— fires when a new comment has been added for a translation key.project.translation.updated
— fires when a translation was modified in a project.project.translation.proofread
— fires when a translation has been marked as reviewed in a project.project.contributor.added
— fires when a new contributor was added to a project by invitation of an admin.project.contributor.added_public
— fires when a new contributor added themselves to a project through the public signup link.project.contributor.deleted
— fires when a contributor was removed from a project.project.task.created
— fires when a new translation or review task was created in a project.project.task.queued
— fires when a newly created task has been queued. Please note that a task will be queued when the following conditions are met:- This is a review task
- It has a parent task or a parent translation order
- Its parent has at least one language that is not yet marked as completed (or a translation order is not marked as completed yet)
project.task.closed
— fires when a task has been marked as closed. Tasks can be closed manually by project admins or automatically upon completion.project.task.deleted
— fires when a task has been deleted.project.task.language.closed
— fires when a language added to a task has been closed. A language can be closed manually or automatically upon completion.project.task.initial_tm_leverage.calculated
— fires when an initial translation memory leverage has been calculated for a task. This calculation is performed automatically.team.order.created
— fires when a new translation order has been created.team.order.completed
— fires when a translation order has been marked as completed.team.order.deleted
— fires when a translation order has been deleted.
Webhook payload examples
// project.imported:
{
"event": "project.imported",
"import": {
"filename": "en.json",
"format": "json",
"inserted": 231,
"updated": 0,
"skipped": 0
},
"project": {
"id": "138c1ffa0ad94848f01f980e7f2f2af19d1bd553",
"name": "TheApp Project"
},
"user": {
"email": "[email protected]",
"full_name": "John Doe"
},
"created_at": "2019-07-29 12:18:31",
"created_at_timestamp": 1564395511
}
// project.exported:
{
"event": "project.exported",
"export": {
"type": "json",
"filename": "files/export/138c1ffa0ad94848f01f980e7f2f2af19d1bd553/67d1a7ff9cab3a57e32ea71c4561a58d/locales.zip",
"platform": "Web"
},
"project": {
"id": "138c1ffa0ad94848f01f980e7f2f2af19d1bd553",
"name": "TheApp Project"
},
"user": {
"email": "[email protected]",
"full_name": "John Doe"
},
"created_at": "2019-07-29 12:18:31",
"created_at_timestamp": 1564395511
}
// project.deleted:
{
"event": "project.deleted",
"project": {
"id": "123.abc",
"name": "Sample project"
},
"user": {
"full_name": "John Doe",
"email": "[email protected]"
},
"created_at": "2019-07-29 12:18:31",
"created_at_timestamp": 1564395511
}
// project.snapshot:
{
"event": "project.snapshot",
"project": {
"id": "138c1ffa0ad94848f01f980e7f2f2af19d1bd553",
"name": "TheApp Project"
},
"user": {
"email": "[email protected]",
"full_name": "John Doe"
},
"created_at": "2019-07-29 12:18:31",
"created_at_timestamp": 1564395511
}
// project.branch.added:
{
"event": "project.branch.added",
"project": {
"id": "123.abc",
"name": "Sample Project"
},
"branch": {
"name": "develop"
},
"user": {
"full_name": "John Doe",
"email": "[email protected]"
},
"created_at": "2019-07-29 12:18:31",
"created_at_timestamp": 1564395511
}
// project.branch.deleted:
{
"event": "project.branch.deleted",
"project": {
"id": "123.abc",
"name": "Sample Project"
},
"branch": {
"name": "develop"
},
"user": {
"full_name": "John Doe",
"email": "[email protected]"
},
"created_at": "2019-07-29 12:18:31",
"created_at_timestamp": 1564395511
}
// project.branch.merged:
{
"event": "project.branch.merged",
"project": {
"id": "123.abc",
"name": "Sample Project"
},
"branch": {
"name": "develop"
},
"target_branch": {
"name": "sprint_20210103"
},
"affected_keys": {
"inserted_count": 4,
"updated_count": 10
},
"user": {
"full_name": "John Doe",
"email": "[email protected]"
},
"created_at": "2019-07-29 12:18:31",
"created_at_timestamp": 1564395511
}
// project.languages.added:
{
"event": "project.languages.added",
"languages": [
{
"id": 734,
"iso": "it",
"name": "Italian"
}
],
"project": {
"id": "138c1ffa0ad94848f01f980e7f2f2af19d1bd553",
"name": "TheApp Project"
},
"user": {
"email": "[email protected]",
"full_name": "John Doe"
},
"created_at": "2019-07-29 12:18:31",
"created_at_timestamp": 1564395511
}
// project.language.removed:
{
"event": "project.language.removed",
"language": {
"id": 734,
"iso": "it",
"name": "Italian"
},
"project": {
"id": "138c1ffa0ad94848f01f980e7f2f2af19d1bd553",
"name": "TheApp Project"
},
"user": {
"email": "[email protected]",
"full_name": "John Doe"
},
"created_at": "2019-07-29 12:18:31",
"created_at_timestamp": 1564395511
}
// project.language.settings_changed:
{
"event": "project.language.settings_changed",
"language": {
"id": 734,
"iso": "it",
"name": "Italian"
},
"project": {
"id": "138c1ffa0ad94848f01f980e7f2f2af19d1bd553",
"name": "TheApp Project"
},
"user": {
"email": "[email protected]",
"full_name": "John Doe"
},
"created_at": "2019-07-29 12:18:31",
"created_at_timestamp": 1564395511
}
// project.key.added:
{
"event": "project.key.added",
"key": {
"id": 16307699,
"name": "test.title",
"base_value": "Hello, world!",
"tags": [
"home"
]
},
"project": {
"id": "138c1ffa0ad94848f01f980e7f2f2af19d1bd553",
"name": "TheApp Project"
},
"user": {
"email": "[email protected]",
"full_name": "John Doe"
},
"created_at": "2019-07-29 12:18:31",
"created_at_timestamp": 1564395511
}
// project.keys.added:
{
"event": "project.keys.added",
"keys": [
{
"id": 28707699,
"name": "test.title",
"base_value": "Hello, world!",
"tags": [
"home_page"
]
},
{
"id": 28746571,
"name": "test.line1",
"base_value": "How are you?",
"tags": [
"home_page"
]
},
{
"id": 28745716,
"name": "test.line2",
"base_value": "It's good to see you.",
"tags": [
"home_page"
]
}
],
"project": {
"id": "138c1ffa0ad94848f01f980e7f2f2af19d1bd553",
"name": "TheApp Project"
},
"user": {
"email": "[email protected]",
"full_name": "John Doe"
},
"created_at": "2023-03-07 12:02:01",
"created_at_timestamp": 1678186921
}
// project.key.modified:
{
"event": "project.key.modified",
"key": {
"id": 16307699,
"name": "test.title_modified",
"previous_name": "test.title",
"filenames": {
"ios": "ios_%LANG_ISO%.strings",
"android": null,
"web": "%LANG_ISO%.json",
"other": null
}
},
"project": {
"id": "138c1ffa0ad94848f01f980e7f2f2af19d1bd553",
"name": "TheApp Project"
},
"user": {
"email": "[email protected]",
"full_name": "John Doe"
},
"created_at": "2019-07-29 12:18:31",
"created_at_timestamp": 1564395511
}
// project.keys.deleted:
{
"event": "project.keys.deleted",
"keys": [
{
"id": 16307699,
"name": "test.title_modified",
"filenames": {
"ios": "ios_%LANG_ISO%.strings"
}
},
{
"id": 16307700,
"name": "test.to_delete"
}
],
"project": {
"id": "138c1ffa0ad94848f01f980e7f2f2af19d1bd553",
"name": "TheApp Project"
},
"user": {
"email": "[email protected]",
"full_name": "John Doe"
},
"created_at": "2019-07-29 12:18:31",
"created_at_timestamp": 1564395511
}
// project.key.comment.added:
{
"event": "project.key.comment.added",
"comment": {
"value": "My comment to test.title key"
},
"key": {
"id": 16307701,
"name": "test.title",
"filenames": {
"android": "filename1",
"ios": "filename2",
"other": "filename3",
"web": "filename4"
}
},
"project": {
"id": "138c1ffa0ad94848f01f980e7f2f2af19d1bd553",
"name": "TheApp Project"
},
"user": {
"email": "[email protected]",
"full_name": "John Doe"
},
"created_at": "2019-07-29 12:18:31",
"created_at_timestamp": 1564395511
}
// project.translation.updated:
{
"event": "project.translation.updated",
"translation": {
"id": 84835169,
"value": "Hello, %s!",
"previous_value": "Hi!"
},
"language": {
"id": 640,
"iso": "en",
"name": "English"
},
"key": {
"id": 16307701,
"name": "test.title"
},
"project": {
"id": "138c1ffa0ad94848f01f980e7f2f2af19d1bd553",
"name": "TheApp Project"
},
"user": {
"email": "[email protected]",
"full_name": "John Doe"
},
"created_at": "2019-07-29 12:18:31",
"created_at_timestamp": 1564395511
}
// project.translation.proofread:
{
"event": "project.translation.proofread",
"translation": {
"id": 84835169,
"value": "Hello, %s!",
"is_proofread": true
},
"language": {
"id": 640,
"iso": "en",
"name": "English"
},
"key": {
"id": 16307701,
"name": "test.title"
},
"project": {
"id": "138c1ffa0ad94848f01f980e7f2f2af19d1bd553",
"name": "TheApp Project"
},
"user": {
"email": "[email protected]",
"full_name": "John Doe"
},
"created_at": "2019-07-29 12:18:31",
"created_at_timestamp": 1564395511
}
// project.contributor.added:
{
"event": "project.contributor.added",
"contributor": {
"email": "[email protected]"
},
"project": {
"id": "138c1ffa0ad94848f01f980e7f2f2af19d1bd553",
"name": "TheApp Project"
},
"user": {
"email": "[email protected]",
"full_name": "John Doe"
},
"created_at": "2019-07-29 12:18:31",
"created_at_timestamp": 1564395511
}
// project.contributor.deleted:
{
"event": "project.contributor.deleted",
"contributor": {
"email": "[email protected]"
},
"project": {
"id": "138c1ffa0ad94848f01f980e7f2f2af19d1bd553",
"name": "TheApp Project"
},
"user": {
"email": "[email protected]",
"full_name": "John Doe"
},
"created_at": "2019-07-29 12:18:31",
"created_at_timestamp": 1564395511
}
// project.task.created:
{
"event": "project.task.created",
"task": {
"id": 5022,
"type": "translation", // supported types are "translation" and "review"
"title": "Headings translation",
"due_date": "2019-08-01 00:00:00",
"description": "Task description"
},
"project": {
"id": "138c1ffa0ad94848f01f980e7f2f2af19d1bd553",
"name": "TheApp Project"
},
"user": {
"email": "[email protected]",
"full_name": "John Doe"
},
"created_at": "2019-07-29 12:18:31",
"created_at_timestamp": 1564395511
}
// project.task.closed:
{
"event": "project.task.closed",
"task": {
"id": 5022,
"type": "translation", // supported types are "translation" and "review"
"title": "Headings translation",
"due_date": "2019-08-01 00:00:00",
"description": "Task description"
},
"project": {
"id": "138c1ffa0ad94848f01f980e7f2f2af19d1bd553",
"name": "TheApp Project"
},
"user": {
"email": "[email protected]",
"full_name": "John Doe"
},
"created_at": "2019-07-29 12:18:31",
"created_at_timestamp": 1564395511
}
// project.task.deleted:
{
"event": "project.task.deleted",
"task": {
"id": 5022,
"title": "Headings translation",
"due_date": "2019-08-01 00:00:00",
"description": "Task description"
},
"project": {
"id": "138c1ffa0ad94848f01f980e7f2f2af19d1bd553",
"name": "TheApp Project"
},
"user": {
"email": "[email protected]",
"full_name": "John Doe"
},
"created_at": "2019-07-29 12:18:31",
"created_at_timestamp": 1564395511
}
// project.task.language.closed:
{
"event": "project.task.language.closed",
"language": {
"id": 640,
"iso": "en",
"name": "English"
},
"task": {
"id": 5022,
"type": "translation", // supported types are "translation" and "review"
"title": "Headings translation",
"due_date": "2019-08-01 00:00:00",
"description": "Task description"
},
"project": {
"id": "138c1ffa0ad94848f01f980e7f2f2af19d1bd553",
"name": "TheApp Project"
},
"user": {
"email": "[email protected]",
"full_name": "John Doe"
},
"created_at": "2019-07-29 12:18:31",
"created_at_timestamp": 1564395511
}
// team.order.created:
{
"event": "team.order.created",
"project": {
"id": "138c1ffa0ad94848f01f980e7f2f2af19d1bd553",
"name": "TheApp Project"
},
"order": {
"id": "20101010D85",
"provider": "lokalise",
"currency": "USD",
"total": 10.00
},
"user": {
"email": "[email protected]",
"full_name": "John Doe"
},
"created_at": "2019-07-29 12:18:31",
"created_at_timestamp": 1564395511
}
// team.order.deleted:
{
"event": "team.order.deleted",
"project": {
"id": "123.abc",
"name": "Sample project"
},
"user": {
"full_name": "John Doe",
"email": "[email protected]"
},
"created_at": "2019-07-29 12:18:31",
"created_at_timestamp": 1564395511
}
// team.order.completed:
{
"event": "team.order.completed",
"project": {
"id": "138c1ffa0ad94848f01f980e7f2f2af19d1bd553",
"name": "TheApp Project"
},
"order": {
"id": "20101010D85",
"provider": "lokalise"
},
"created_at": "2019-07-29 12:18:31",
"created_at_timestamp": 1564395511
}
// project.task.initial_tm_leverage.calculated:
{
"event": "project.task.initial_tm_leverage.calculated",
"task": {
"id": 12345,
"title": "New task",
"description": "Please translate as soon as possible",
"initial_tm_leverage": {
"600": {
"0": 154,
"50": 5,
"75": 4,
"85": 11,
"95": 0,
"100%": 6
},
"1056": {
"0": 158,
"50": 17,
"75": 0,
"85": 0,
"95": 2,
"100%": 3
}
}
},
"project": {
"id": "138c1ffa0ad94848f01f980e7f2f2af19d1bd553",
"name": "TheApp Project",
"branch": "master"
},
"created_at": "2021-03-30 16:01:11",
"created_at_timestamp": 1617112871
}
Receiving webhooks (example in PHP)
<?php
$input = @file_get_contents("php://input");
$data = json_decode($input, true);
http_res
Updated 1 day ago