Webhook Headers

All the webhooks we send back to the callback URL are signed by using HMAC.

HMAC works by combining a key and the body of the message into a single hash using any given hashing algorithm (in this our SHA256) In our case, the key is the OAuth UUID of your integration — the value shown next to the Secret when you generate your keys in the Integrations section, and the one you send as client_id when requesting an access token. Only you and Cabify know it. By calculating the HMAC code and checking that it matches the one sent by Cabify, you can be sure the message has been sent by Cabify and has not been tampered with.

❗️

Two different identifiers

The signing key is not the client_id you will find in data.client_id and in the X-CABIFY-CLIENT-ID header. Those carry your Cabify account identifier, which is public. The signing key is your integration's OAuth UUID, which is secret.

This is why the two values differ in the example below, and it is deliberate: never use the account identifier to verify a signature.

Let's apply it to an example, given the post-body:

{
   "type":"journey-state",
   "errors":[],
   "data":{
      "user_id":"0d3cd443da5f11eb89d7ea639ff4befb",
      "terminated_at":"2021-09-10T15:37:53Z",
      "state":"terminated",
      "start_type":"asap",
      "start_at":"2021-09-10T15:19:27Z",
      "rider_id":"0d3cd443da5f11eb89d7ea639ff4befb",
      "journey_id":"7ca6d170-124a-11ec-a51b-eee256348c41",
      "finished_at":null,
      "finish_reason":"drop off",
      "event_date":"2021-09-10T15:37:53.890Z",
      "driver_id":null,
      "created_at":"2021-09-10T15:19:27Z",
      "client_id":"0d324c00da5f11eb89d7ea639ff4befb"
   }
}
🚧

Remove blanks

Please note that the blanks must be removed when coding the body.
Only the spaces between the attributes should be eliminated, but not the spaces between the values contained in the attributes. Look at the finish_reason attribute in the following example:

{"type":"journey-state","errors":[],"data":{"user_id":"0d3cd443da5f11eb89d7ea639ff4befb","terminated_at":"2021-09-10T15:37:53Z","state":"terminated","start_type":"asap","start_at":"2021-09-10T15:19:27Z","rider_id":"0d3cd443da5f11eb89d7ea639ff4befb","journey_id":"7ca6d170-124a-11ec-a51b-eee256348c41","finished_at":null,"finish_reason":"drop off","event_date":"2021-09-10T15:37:53.890Z","driver_id":null,"created_at":"2021-09-10T15:19:27Z","client_id":"0d324c00da5f11eb89d7ea639ff4befb"}}

With the integration's OAuth UUID being 0e5877578e4f427f8341c09a85ac4d20. Note that it is a different value from the client_id in the body (0d324c00da5f11eb89d7ea639ff4befb), which is the account identifier.

The resulting HMAC using the SHA256 function will be:

6b66c5a3dd02e49e3b14746754ccbb8ef98e2d0108eb5422f0dee244dbb4b547

The fully built header will be:

'X-CABIFY-SIGNATURE:sha256=6b66c5a3dd02e49e3b14746754ccbb8ef98e2d0108eb5422f0dee244dbb4b547'

The way to check the validity of the message is to compute the HMAC code on the customers side and checking that it matches the HMAC code set in the header.

You can do a quick test with the following online tool: https://www.freeformatter.com/hmac-generator.html#ad-output

Account identification header (X-CABIFY-CLIENT-ID)

Every webhook we send also includes an X-CABIFY-CLIENT-ID header carrying the public client_id of the Cabify account the event belongs to. This identifies the account, not the integration, so it is a different value from the OAuth UUID used to sign the request:

'X-CABIFY-CLIENT-ID:0d324c00da5f11eb89d7ea639ff4befb'

This is the same value already present in the body as data.client_id, exposed as a header so you can identify which account an event belongs to without parsing the request body — useful, for example, when a single integration handles multiple accounts.

🔒

Security

Only the public account client_id is sent in this header. The OAuth UUID used as the HMAC key is never transmitted — it stays a shared secret known only to you and Cabify.

Encoding example

Did this page help you?