# Introduction

## Overview

Webhooks allow the Mobile Calendar API to send real-time notifications to your system whenever specific events occur. Instead of polling the API for updates, your application receives HTTP POST requests directly from the Mobile Calendar server.

Webhooks are ideal for synchronizing data in real time, triggering automations, and keeping external systems (like PMS, CRMs, or custom tools) up to date.

## How It Works

{% stepper %}
{% step %}

### Register an endpoint

You register a webhook endpoint URL in your integration settings.
{% endstep %}

{% step %}

### Event occurs

When a subscribed event occurs (e.g., `reservation.created`), Mobile Calendar sends a POST request to your endpoint.
{% endstep %}

{% step %}

### Receive minimal payload

The request contains a minimal JSON payload identifying the event type and related object.
{% endstep %}

{% step %}

### Verify signature

You verify the request signature to ensure authenticity.
{% endstep %}

{% step %}

### Fetch detailed data

You fetch detailed data using the appropriate GET API endpoint.
{% endstep %}

{% step %}

### Acknowledge receipt

Your server must respond with HTTP 2xx to confirm receipt.
{% endstep %}
{% endstepper %}

Webhooks are queued and delivered asynchronously. In most cases, they are sent within seconds, but under load or retries, delays of up to 2 minutes are possible.

## Delivery and Retry Policy

Webhooks are retried automatically if your server **does not respond with a 2xx code or times out (>10s).**

| Attempt |      Delay |
| ------: | ---------: |
|     1st |  Immediate |
|     2nd |  +1 minute |
|     3rd | +5 minutes |
|     4th |    +1 hour |
|     5th |  +12 hours |
|     6th |  +24 hours |

After 6 failed attempts, the webhook is marked as **undeliverable** and will not be retried further.

## Webhook Payload Example

<mark style="color:green;">`POST`</mark>&#x20;

**Headers**

| Name             | Value                                |
| ---------------- | ------------------------------------ |
| Content-Type     | `application/json`                   |
| X-MC-Event       | reservation.created                  |
| X-MC-Signature   | sha256=ab4d5a67b12f...               |
| X-MC-Delivery-ID | 123e4567-e89b-12d3-a456-426614174000 |

**Body**

| Name         | Type                                   | Description                                                                                                                                                                                                                                                                                                                                                                |
| ------------ | -------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `webhookId`  | string (UUID v4)                       | Unique identifier of this webhook delivery. It is **stable across retries** of the same event so you can de-duplicate safely                                                                                                                                                                                                                                               |
| `eventType`  | string (ENUM)                          | The event name that triggered this webhook example: `reservation.created`                                                                                                                                                                                                                                                                                                  |
| `timestamp`  | string (ISO 8601 with timezone offset) | The time **the event occurred in our system**, not the time your server received it.                                                                                                                                                                                                                                                                                       |
| `data`       | object or array                        | <p>The <code>data</code> object contains the <strong>minimal payload</strong> describing the resource affected by the event.<br>It includes only key identifiers and metadata necessary to determine <em>what happened</em> and <em>to which object</em>.<br>Full details should always be fetched from the API using the URL provided in <code>data.links.self</code></p> |
| `data.links` | object or array                        | <p>The <code>links</code> object provides <strong>HATEOAS-style links</strong> to related resources.<br>It allows the receiver to easily fetch the full object affected by the event.</p>                                                                                                                                                                                  |

**Payload**

{% tabs %}
{% tab title="JSON body" %}

```json
{
   "webhookId":"9b9b499e-095c-4955-8dd0-cc5d84e50764",
   "eventType":"reservation.created",
   "timestamp":"2025-10-10T15:39:07+02:00",
   "data":{
      "type":"SINGLE",
      "reservationId":[
         478652
      ],
      "roomId":[
         28568
      ],
      "arrival":"2025-10-14",
      "departure":"2025-10-16",
      "clientId":362792,
      "triggeredBy":"MANUAL",
      "sourceId":3,
      "links":{
         "self":"https://apisandbox.mobile-calendar.com/v1/reservations/478652"
      }
   }
}
```

{% endtab %}
{% endtabs %}

## Security and Privacy

Webhooks include a digital signature to verify authenticity. Use your webhook secret key to compute an HMAC-SHA256 hash of the payload.

Example:

{% code lineNumbers="true" %}

```typescript
import crypto from 'crypto';

export function verifyWebhookSignature(rawBodyBuffer, signatureHeader, secret) {
  if (!signatureHeader || !signatureHeader.startsWith('sha256=')) return false;
  const providedHex = signatureHeader.slice('sha256='.length);
  if (!/^[0-9a-fA-F]+$/.test(providedHex)) return false;

  // Compute expected MAC over the exact raw bytes
  const expected = crypto.createHmac('sha256', secret).update(rawBodyBuffer).digest(); // Buffer
  const provided = Buffer.from(providedHex, 'hex');

  // Length must match; compare in constant time
  if (provided.length !== expected.length) return false;
  return crypto.timingSafeEqual(provided, expected);
}
```

{% endcode %}

For security and privacy, webhook payloads **do not include full entity data**. You should always fetch detailed data through the REST API after verifying the webhook.

{% hint style="warning" %}
Always verify the HMAC SHA-256 signature from the `X-Webhook-Signature` header before trusting payload contents.
{% endhint %}

## Recommended Processing Flow

{% stepper %}
{% step %}

### Receive webhook

Your endpoint gets a POST request.
{% endstep %}

{% step %}

### Verify signature

Verify signature using your secret key.
{% endstep %}

{% step %}

### Acknowledge quickly

Acknowledge receipt quickly (respond 200 OK).
{% endstep %}

{% step %}

### Fetch full data

Fetch full data from the appropriate API endpoint.
{% endstep %}

{% step %}

### Update local system

Update your local system (e.g., database, cache).
{% endstep %}

{% step %}

### Log for audit

Log the `ruid` and event details for audit purposes.
{% endstep %}
{% endstepper %}

Do not rely solely on the webhook payload — always retrieve data directly from the API.

## Best Practices

* Always respond with HTTP **2xx** to confirm successful receipt.
* Retry processing should be **idempotent** — handle duplicates safely.
* Use **HTTPS** and IP whitelisting for security.
* Avoid blocking operations — handle processing asynchronously.
* Validate the event type before acting on it.
* Use exponential backoff or queues for downstream API calls.
* Regularly monitor undelivered webhook events in your integration logs.

## Summary

Webhooks are an essential component for real-time data synchronization between Mobile Calendar and external systems. They are secure, signed, reliable, and asynchronous, ensuring that all critical events are eventually delivered even if temporary issues occur.

By correctly implementing webhook handling, you ensure your integration stays perfectly synchronized without unnecessary polling.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://mobile-calendar.gitbook.io/v1/webhooks/introduction.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
