About webhooks #️⃣

You must be subscribed to the Autopilot or a higher tier to set up webhooks. Webhook configuration is also available in the Localazy web UI.

When the event occurs, all URLs with the given event configured are called with a POST request. The header Content-Type is set to application/json and in the POST body, a JSON structure with additional information is provided. Timeouts are set to 10 seconds. Redirects are enabled.

Security #️⃣

Localazy signs the webhook events it sends to your endpoints and adds a signature in the request header. This allows you to verify that the events were sent by Localazy and not a third party.

Header name Description Type
X-Localazy-Timestamp UNIX timestamps in seconds string
X-Localazy-HMAC HMAC SHA 256 of “{ts}-{raw post body}” signed by secret string

How to verify webhook requests?

Before you can verify signatures, you need to retrieve your project secret using the webhook secret endoint.

To verify that the request sent is valid (and therefore has not been modified during the transfer) calculate the hash of the request, and compare it with the value stored in the X-Localazy-HMAC header:

const crypto = require("crypto");

// `secret` fetched with the /projects/{projectId}/webhooks/secret endpoint
const secretHmac = crypto.createHmac("sha256", secret);
// `xLocalazyTimestamp`: X-Localazy-Timestamp header value
// `body` the webhook POST body
const signedMessage = secretHmac.update(`${xLocalazyTimestamp}-${JSON.stringify(body)}`).digest("hex");

// `xLocalazyHmac`: X-Localazy-HMAC header value
if (xLocalazyHmac !== signedMessage) {
  // processing the request is not recommended, reqeuest has been modified
}

// request can be safely processed

List webhooks configuration #️⃣

[GET] /projects/{projectId}/webhooks
Type Value
Roles reviewer
Produces application/json

Returns the webhooks configuration for the given project.

Params

Sample Request #️⃣

curl --request GET \
  --url https://api.localazy.com/projects/{projectId}/webhooks \
  --header 'Authorization: Bearer {{token}}'

Sample Response #️⃣

{
  "items": [
    {
      "enabled": true,
      "customId": "my-custom-id",
      "description": "Inform backend that the project is published.",
      "url": "https://webhook-target-url.com/webhook1",
      "events": [
        "project_published"
      ]
    },
    {
      "enabled": false,
      "customId": "",
      "description": "",
      "url": "https://webhook-target-url.com/webhook2",
      "events": [
        "project_published"
      ]
    }
  ]
}

Response Object

Field Description
enabled Wheter the webhook is enabled or disabled.
customId Custom ID that is passed when the webhook is invoked. Empty by default.
description Description of the webhook. Empty by default.
url URL which is invoked on the webhook event.
events The list of event types for which this webhook is invoked.

Update webhooks configuration #️⃣

[POST] /projects/{projectId}/webhooks
Type Value
Roles reviewer
Produces application/json
Consumes application/json

Store a new webhooks configuration for the project. You can use project’s id or slug as {projectId}.

Limits:

  • There can be max. 30 webhooks per project.
  • URL can be max. 1024 chars long.
  • There can be max. of 50 events per webhook.
  • Event can be max. 32 chars long.

Sample Request #️⃣

curl --request POST \
  --url https://api.localazy.com/projects/{projectId}/webhooks \
  --header 'Authorization: Bearer {{token}}' \
  --header 'Content-Type: application/json' \
  --data '{ 
  "items": [
    {
      "enabled": true,
      "customId": "my-custom-id",
      "description": "Inform backend that the project is published.",
      "url": "https://webhook-target-url.com/webhook1",
      "events": [
        "project_published"
      ]
    },
    {
      "enabled": false,
      "customId": "",
      "description": "",
      "url": "https://webhook-target-url.com/webhook2",
      "events": [
        "project_published"
      ]
    }
  ]
}'

Request Object

Field Description
enabled Allows to enabled/disable the webhook.
customId Custom ID that is passed when the webhook is invoked. Empty by default.
description Description of the webhook. Empty by default.
url URL to be invoked on the webhook event.
events The list of event types to invoke this webhook for.

Sample Response #️⃣

{
  "result": true
}
Field Description
result Success status of operation

Event Types #️⃣

List of events that can be triggered by the webhook. Can be one of [comment_added, import_finished, import_finished_empty, project_published, tag_promoted].

Comment Added #️⃣

  • Idenfitier: comment_added
  • Triggered when a comment is added to the specified project

Request Body

{
  "type": "comment_added",
  "projectId": "_a8402929705887203313",
  "customId": "",
  "phraseId": "_a8402929700326342655",
  "langId": 60,
  "locale": "cs",
  "text": "Text of the comment...",
  "url": "https://localazy.com/p/test-project/phrases/60/edit/_a8402929700326342655",
  "user": {
    "id": "_a8402929715013877756",
    "image": "",
    "name": "John Doe",
    "slug": "john-doe"
  }
}
Field Description
type Webhook event type
projectId the Localazy project identifier
customId the webhook identifier (empty when defined in UI, modifiable over Public API)
phraseId the phrase identifier the comment belongs to
langId the language identifier the comment belongs to
locale the locale code the comment belongs to
text the comment text
url the comment URL
user an object containing the basic commenting user information. See User Object below.

User Object

Field Description
id the user identifier
image the user image
name the user name
slug the user slug

Content Imported #️⃣

  • Identifier: import_finished
  • The webhook is invoked when importing is finished (from CLI or Gradle). Event import_finished is invoked only when there are added, updated or deprecated keys.

Request Body

{
  "type": "import_finished",
  "projectId": "_a8402929705887203313",
  "customId": "",
  "added": 5,
  "updated": 1,
  "deprecated": 3
}
Field Description
type Webhook event type
projectId the Localazy project identifier
customId the webhook identifier (empty when defined in UI, modifiable over Public API)
added number of newly added keys
updated number of newwly updated keys
deprecated number of deprecated keys

Content Imported Empty #️⃣

  • Identifier: import_finished_empty
  • The webhook is invoked when importing is finished (from CLI or Gradle). This event is invoked when the importing finished with no changes.

Request Body

{
  "type": "import_finished_empty",
  "projectId": "_a8402929705887203313",
  "customId": "",
  "added": 0,
  "updated": 0,
  "deprecated": 5
}
Field Description
type Webhook event type
projectId the Localazy project identifier
customId the webhook identifier (empty when defined in UI, modifiable over Public API)
added number of newly added keys
updated number of newwly updated keys
deprecated number of deprecated keys

Project Published #️⃣

  • Identifier: project_published
  • Triggered when the project is successfully published (applies to release tags too)

Request Body

{
  "type": "project_published",
  "projectId": "_a8404215906455781329",
  "customId": "custom ID",
  "tag": "latest"
}
Field Description
type Webhook event type
projectId the Localazy project identifier
customId the webhook identifier (empty when defined in UI, modifiable over Public API)
tag the latest tag or a tag created by Released Tags

Tag Promoted #️⃣

  • Identified: tag_promoted
  • Triggered whenever a release tag is promoted to another tag (see release tags)

Request Body

{
  "type" : "tag_promoted",
  "projectId" : "_a8404215906455781329",
  "customId": "custom ID",
  "sourceTag" : "latest",
  "targetTag" : "production"
}

Webhook secrets #️⃣

[GET] /projects/{projectId}/webhooks/secret

Retrieve webhooks secret for current project.

Request #️⃣

curl --request GET \
  --url https://testing.localazy.com/api/project/test-project/webhooks/secret \
  --header 'Authorization: Bearer {{token}}'

Response #️⃣

{
  "secret": "a webhook secret",
}