# Receive booking status webhook

URL: https://docs.emergingtravel.com/docs/affiliate-api/booking/receive-booking-status-webhook/

Tags: affiliate

---


> [!NOTE]
> <strong>This call is required</strong> if you don’t use the [Check booking process](/docs/affiliate-api/booking/check-booking-process/) call.



The call retrieves a webhook for the booking process status via the POST method.

## Sandbox limitations { #limitations }

No changes.

## Getting webhook scenario

1. Provide the callback URL to the API support team.
1. The API support team sets up the callback URL.
1. Once the callback URL is set and the booking process is finished, the ETG API sends the webhook.
1. Check if the webhook is received on your side and send the appropriate response.

> [!NOTE]
> At the last second, request this call for the last time and receive the status:
>   * `completed` — the booking finishing will end with success.
>   * `failed` — the booking finishing will end with an error.



## Your server responses

The ETG listens to the following codes from your server and reacts accordingly:
* Code 200 — the webhook is received successfully and doesn’t need a retry.
* Any code greater than 299 (including 4xx and 5xx responses) — the ETG will retry sending the webhook.

Retries are performed with increasing intervals, depending on the number of previous attempts:
1. 30 seconds.
1. 60 seconds.
1. 90 seconds.
1. 120 seconds.
1. 150 seconds.
1. 300 seconds (5 minutes).
1. 1 hour.
1. 12 hours.

After the 7th attempt, all subsequent retries will be performed every 12 hours, up to a total of 21 retry attempts.

## Payload



- **partner_order_id** *(String, required)*

  <p>The unique partner booking ID.</p>
  > [!NOTE]
  > * The minimum length is `1` character.
  > * The maximum length is `256` characters.


- **status** *(String, required)*

  <p>The booking finishing status.</p>
  > [!NOTE]
  > * The possible values:
  >   * `completed` — the booking finishing has ended with success.
  >   * `failed` — the booking finishing has ended with an error.
  >   
  >   To know the reason for the failure, use the [Check booking process](/docs/affiliate-api/booking/check-booking-process/) call.





The payload example:

```json
{
  "partner_order_id": "0b370500-5321-4046-92c5-5982f1a64fc6",
  "status": "completed"
}
```

## Secure data



- **signature** *(String, required)*

  <p>The hexadecimal digits generated by the [HMAC algorithm](https://en.wikipedia.org/wiki/HMAC)
  
  .</p>


- **timestamp** *(Int, required)*

  <p>The date and time of creating a webhook token in the [Unix Timestamp](https://www.unixtimestamp.com/)
   format.</p>
  > [!NOTE]
  > * The minimum date is January 1, 1970.
  > * You can find it in the token signature when decoding.


- **token** *(String, required)*

  <p>The randomly generated string with the length of 50 characters.</p>





The secure data example:

```json
{
  "signature": {
    "signature": "7865d225dbee1b54909er153d193e0b57b707ebe81ff5b2e1b71ebaf749bec23",
    "timestamp": 1574146939,
    "token": "d3395025-1ee7-49a2-bd86-e4bd6b9908b2"
  }
}
```

## Whole fields example

```json
{
  "data": {
    "partner_order_id": "0b370500-5321-4046-92c5-5982f1a64fc6",
    "status": "completed"
  },
  "signature": {
    "signature": "7865d225dbee1b54909er153d193e0b57b707ebe81ff5b2e1b71ebaf749bec23",
    "timestamp": 1574146939,
    "token": "d3395025-1ee7-49a2-bd86-e4bd6b9908b2"
  }
}
```

## Signature verification

To verify the webhook issued by the ETG:

1. Concatenate the timestamp and token values. The “token” means the one sent by the ETG in the webhook data.
1. Encode the resulting string with the [HMAC algorithm](https://en.wikipedia.org/wiki/HMAC):
  1. Use your [API Key token](/docs/glossary/#api-key-token) as a key.
  1. Use the SHA256 digest mode.
1. Use the `hexdigest()` method to make a resulting string.
1. Compare the resulting string to the signature.
1. <strong>Optional.</strong> Cache the token locally and don’t honor any subsequent request with the same token. This will prevent replay attacks.
1. <strong>Optional.</strong> Check that the timestamp is within the token lifetime.

## Examples

### Python

```python
import hashlib, hmac
def verify(api_key, token, timestamp, signature):
    hmac_digest = hmac.new(key=api_key,
                           msg='{}{}'.format(timestamp, token),
                           digestmod=hashlib.sha256).hexdigest()
    return hmac.compare_digest(unicode(signature), unicode(hmac_digest))
```

### Ruby

```ruby
require 'openssl'
def verify(api_key, token, timestamp, signature)
  digest = OpenSSL::Digest::SHA256.new
  data = [timestamp, token].join
  signature == OpenSSL::HMAC.hexdigest(digest, api_key, data)
end
```

### PHP

```php
function verify($apiKey, $token, $timestamp, $signature)
{
  // check if the timestamp is fresh
  if (abs(time() - $timestamp) > 15) {
    return false;
  }
  // returns true if signature is valid
  return hash_hmac('sha256', $timestamp . $token, $apiKey) === $signature;
}
```

### Node.js

```js
const crypto = require('crypto')
const verify = ({ apiKey, timestamp, token, signature }) => {
    const encodedToken = crypto
        .createHmac('sha256', apiKey)
        .update(timestamp.toString().concat(token))
        .digest('hex')
    return (encodedToken === signature)
}
```
