A webhook is a mechanism to notify external services like chat clients, project management tools or other external APIs of events or changes that happened in PhraseApp. This feature allows you to register a callback URL that will receive a call whenever a certain event takes place in PhraseApp.

It is currently possible to track events of the following types:

  • locales:create - A new Language Version has been created on a project
  • locales:update - A Language Version has been changed, renamed or reconfigured
  • locales:delete - A Language Version has been deleted
  • uploads:create - A Locale File has been uploaded
  • uploads:processing - A Locale File was processed
  • keys:create - A Key has been created
  • keys:update - A Key has been renamed or changed
  • keys:delete - A Key has been deleted
  • keys:batch_delete - Multiple Keys were deleted
  • translations:create - A Translation of a Key in a certain Language Version has been added
  • translations:update - A Translation of a Key in a certain Language Version has been edited
  • translations:deliver - A Translation of a Key in a certain Language Version has been delivered by a language service provider
  • comments:create - A Comment on a Translation Key has been added

Configure a Webhook

A webhook can be configured in your Translation Center as follows:

  1. Go to the “Manage” tab
  2. Select the “Webhook” section
  3. Click the “Add Webhook”-button
  4. Choose one or more events you want to listen for from the dropdown menu
  5. Enter a Callback-URL that will be called by PhraseApp every time an event of the selected event types has occured.
  6. The Translation Center will show a secret that you can use to validate the integrity of the Webhook callbacks

Testing a Webhook

You can test your webhooks in order to verify that the endpoint is receiving the event notification. Just click the “Send test notification”-link. This will send an example event notification to the provided callback URL.

An easy way to capture the contents of a webhook is to use a service like RequestBin. It gives you a URL that will collect requests made to it so that you can easily inspect their content.

Receive Webhooks

Once you register a webhook, we will send a POST request to the specified callback URL every time an event of the specified type occurs. The request’s POST payload is a JSON-encoded document with relevant data for the event. The attributes event and message will always be included with additional relevant resources like the user and project.

Response headers

HTTP requests made to your callback URL will contain several special headers:

Header Description
X-PhraseApp-Event Type of event that triggered this hook.
X-PhraseApp-Signature HMAC hex digest of the payload, using the hook’s secret as the key.

Example Payload

Content-Type: application/json X-PhraseApp-Event: translation:create X-PhraseApp-Signature: abc123
{ "event": "translations:create", "message": "Peter translated page.help.title in fr.", "user": { "id": "abcd1234cdef1234abcd1234cdef1234", "username": "joe.doe", "name": "Joe Doe", "email": "joe@phraseapp.com", "position": "Lead Developer", "created_at": "2015-01-28T09:52:53Z", "updated_at": "2015-01-28T09:52:53Z" }, "project": { "id": "abcd1234cdef1234abcd1234cdef1234", "name": "My Android Project", "main_format": "xml", "account": "account", "created_at": "2015-01-28T09:52:53Z", "updated_at": "2015-01-28T09:52:53Z" }, "translation": { "id": "abcd1234cdef1234abcd1234cdef1234", "content": "My translation", "unverified": false, "excluded": false, "plural_suffix": "", "key": { "id": "abcd1234cdef1234abcd1234cdef1234", "name": "home.index.headline", "plural": false }, "locale": { "id": "abcd1234cdef1234abcd1234cdef1234", "name": "de", "code": "de-DE" }, "placeholders": [ "%{count}" ], "created_at": "2015-01-28T09:52:53Z", "updated_at": "2015-01-28T09:52:53Z" } }

Respond to a Webhook

Your webhook endpoint is required to return a HTTP status in the 2xx range within 5 seconds upon receiving a callback. Any other HTTP status code or a request timeout is considered to be a delivery failure. A webhook will be deactivated if delivery fails for more than 10 consecutive events. Callbacks are not repeated.

If you’re receiving a callback, the most important thing to do is respond within the 5 second request-timeout-period. To make sure that apps do not accidentally trigger a timeout, we recommend that apps defer processing to a time after the http response has been sent.

Verify a Webhook

Each webhook request includes a X-PhraseApp-Signature header which is generated using your app’s shared secret, along with the data sent in the request.

You can verify that the request originated from PhraseApp by computing the HMAC digest of the request body and comparing it to the value in the X-PhraseApp-Signature header.

Example Code

def verify_webhook(signatureheader)
  digest = OpenSSL::Digest::Digest.new('sha256')
  hmac = OpenSSL::HMAC.digest(digest, SHARED_SECRET, request.body)
  hmac = Base64.encode64(hmac).strip
  hmac == signatureheader

function verify_webhook($signatureheader){
  $hmac = hash_hmac('sha256', $requestBody, $sharedSecret, true);
  $hmac = trim(base64_encode($hash));
  return $hmac == $signatureheader;

Integrate with Slack

Slack is a platform for team communication: everything in one place, instantly searchable, available wherever you go. Slack enables integrations that let you automatically pull information and activity from outside tools into Slack in a way that’s timely, relevant and searchable.

To integrate notifications generated by a PhraseApp webhook into a Slack channel you will need to setup an incoming webhook service integration within Slack to obtain your webhook URL as follows:

  1. Go to ‘Add Incoming Webhook’ in your slack account.
  2. Select the desired channel to post to.
  3. Once created, copy the provided Webhook URL and follow the steps describe above to create a webhook within PhraseApp using the Webhook URL as Callback-URL.

We will send a POST request to the provided URL every time an event of the specified type occurs. The request’s POST payload is a JSON-encoded document with relevant data required by Slack to display a short description of the occured event in a dedicated channel.

Example Payload

  "text": "Andre has updated a translation in project: 'my project'",
  "username": "PhraseApp"