# Webhooks

## Webhooks API Documentation

### Introduction

Welcome to the Ayor Webhook API documentation. This guide helps third-party developers integrate with our webhook system to receive real-time event notifications securely and reliably.

***

### Webhook Overview

Webhooks allow your system to receive automated event notifications (such as `order.created`) from Ayor. They are delivered as HTTPS POST requests to your specified endpoint. Events are pushed using Google Pub/Sub.

***

### Event Types

You can subscribe to the following event types:

* `order.created` <i class="fa-check">:check:</i>       &#x20;
* `order.updated` <i class="fa-check">:check:</i>
* `order.confirmed` <i class="fa-clock">:clock:</i>
* `order.shipped` <i class="fa-clock">:clock:</i>
* `order.delivered` <i class="fa-clock">:clock:</i>
* `order.cancelled` <i class="fa-clock">:clock:</i>
* `product.out_of_stock` <i class="fa-clock">:clock:</i>
* `subscription.renewed` <i class="fa-clock">:clock:</i>
* `subscription.expired` <i class="fa-clock">:clock:</i>
* `integration.failed` <i class="fa-clock">:clock:</i>
* `domain.connected` <i class="fa-clock">:clock:</i>

***

### Integration Guide

#### Payload Format

Each webhook event is delivered as a Pub/Sub message structured like this:

```json
{
  "deliveryAttempt": 1,
  "message": {
    "attributes": {
      "event_id": "<uuid>",
      "event_type": "order.created",
      "shop_id": "<uuid>",
      "timestamp": "2025-08-06T15:35:30.491494",
      "user_id": "<id>"
    },
    "data": "<base64-encoded-payload>"
  },
  "subscription": "projects/.../subscriptions/webhook-<user_id>-<event_type>-<hash>"
}
```

#### Decoded Payload Example

The `data` field contains a base64-encoded JSON object. After decoding, here is a sample payload for `order.created`:

```json
{
  "event_id": "77d13351-0578-4f6f-ba5e-fb38405b75ba",
  "event_type": "order.created",
  "user_id": "2734",
  "timestamp": "2025-08-18T10:19:43.760875Z",
  "data": {
    "event_id": "77d13351-0578-4f6f-ba5e-fb38405b75ba",
    "order_id": "10e0e5ff-c844-4ad8-80f5-7024c5df8d39",
    "display_id": 33,
    "confirmation_status": "Pending",
    "delivery_status": null,
    "total_price": 1800,
    "delivery_price": 0,
    "currency": "DZD",
    "payment_method": "cod",
    "payment_status": "pending",
    "is_stop_desk": false,
    "shipping_id": null,
    "client_note": null,
    "created_at": "2025-08-18T10:19:39.680686+00:00",
    "updated_at": "2025-08-18T10:19:39.817185+00:00",
    "client_info": {
      "full_name": "Touares tou",
      "phone_number": "0770707070",
      "email": null,
      "state": "12 - Tébessa - تبسة",
      "city": "بئر العاتر"
    },
    "custom_fields": [
    {
      "field_id": 6,
      "field_name": "Custom",
      "custom_title": "Custom Address",
      "value": "sdfghjk",
      "item_id": null
    }
    ],
    "timestamp": "2025-08-18T10:19:43.757867",
    "order_lines": [
      {
        "product_id": "b26bca7a-35cd-4397-bb5d-c5708a22c58c",
        "product_name": "Aqua di Gio",
        "variant_name": null,
        "quantity": 1,
        "unit_price": 1800,
        "reduced_price": null,
        "total_price": 1800,
        "sku": null,
        "shipping_id": null
      }
    ],
    "bundle_lines": [],
    "shop_info": {
      "shop_id": "52f9c4ea-7cbe-4b32-9696-99e9f32c5daf",
      "shop_name": "store",
      "shop_subdomain": "store"
    },
    "landing_page_info": {
      "landing_page_id": "f29039b5-b670-438a-acd0-c5e88aea5b9a",
      "landing_page_title": "Aqua di Gio"
    }
  }
}
```

#### Payload Schema (Field Reference)

Each event includes a JSON payload with the following fields:

| Field                 | Type                |                    Required                   | Description                                        | Allowed Values                                                           |
| --------------------- | ------------------- | :-------------------------------------------: | -------------------------------------------------- | ------------------------------------------------------------------------ |
| `event_id`            | `string`            | <i class="fa-square-check">:square-check:</i> | Unique identifier of the event                     |                                                                          |
| `event_type`          | `string`            | <i class="fa-square-check">:square-check:</i> | Type of event (e.g., `order.created`)              |                                                                          |
| `user_id`             | `string`            | <i class="fa-square-check">:square-check:</i> | ID of the user (merchant)                          |                                                                          |
| `timestamp`           | `string (ISO 8601)` | <i class="fa-square-check">:square-check:</i> | Time the event was generated                       |                                                                          |
| `order_id`            | `string`            | <i class="fa-square-check">:square-check:</i> | Unique ID of the order                             |                                                                          |
| `display_id`          | `integer`           | <i class="fa-square-check">:square-check:</i> | Merchant-facing order reference number             |                                                                          |
| `confirmation_status` | `string`            | <i class="fa-square-check">:square-check:</i> | Status of order confirmation                       | `Pending`, `Confirmed`, `Callback`, `Cancelled`                          |
| `delivery_status`     | `string or null`    |     <i class="fa-square-x">:square-x:</i>     | Status of delivery, if available                   | `CREATED`, `IN_TRANSIT`, `PENDING`, `DELIVERED`, `CANCELLED`, `RETURNED` |
| `total_price`         | `decimal`           | <i class="fa-square-check">:square-check:</i> | Total order amount including products and delivery |                                                                          |
| `delivery_price`      | `decimal`           | <i class="fa-square-check">:square-check:</i> | Delivery fee                                       |                                                                          |
| `currency`            | `string`            | <i class="fa-square-check">:square-check:</i> | Currency code (e.g., DZD)                          |                                                                          |
| `payment_method`      | `string`            | <i class="fa-square-check">:square-check:</i> | Payment method used                                | `cod`, `stripe`                                                          |
| `payment_status`      | `string`            | <i class="fa-square-check">:square-check:</i> | Status of the payment                              | `pending`, `completed`, `failed`                                         |
| `is_stop_desk`        | `boolean`           | <i class="fa-square-check">:square-check:</i> | Whether the order is a stop-desk pickup            |                                                                          |
| `shipping_id`         | `string or null`    |     <i class="fa-square-x">:square-x:</i>     | Shipping provider ID or tracking ref               |                                                                          |
| `client_note`         | `string or null`    |     <i class="fa-square-x">:square-x:</i>     | Customer-provided message                          |                                                                          |
| `created_at`          | `string (ISO 8601)` | <i class="fa-square-check">:square-check:</i> | Timestamp of order creation                        |                                                                          |
| `updated_at`          | `string (ISO 8601)` | <i class="fa-square-check">:square-check:</i> | Timestamp of last update to the order              |                                                                          |

**`client_info` object**

| Field          | Type             |                    Required                   | Description           |
| -------------- | ---------------- | :-------------------------------------------: | --------------------- |
| `full_name`    | `string`         | <i class="fa-square-check">:square-check:</i> | Customer full name    |
| `phone_number` | `string`         | <i class="fa-square-check">:square-check:</i> | Customer phone number |
| `email`        | `string or null` |     <i class="fa-square-x">:square-x:</i>     | Customer email        |
| `state`        | `string`         | <i class="fa-square-check">:square-check:</i> | Customer state/region |
| `city`         | `string`         | <i class="fa-square-check">:square-check:</i> | Customer city         |

**`custom_fields` array**

Each field added by the merchant to their landing page:

| Field          | Type             |                    Required                   | Description                          |
| -------------- | ---------------- | :-------------------------------------------: | ------------------------------------ |
| `field_id`     | `integer`        | <i class="fa-square-check">:square-check:</i> | ID of the custom form field          |
| `field_name`   | `string`         | <i class="fa-square-check">:square-check:</i> | Name of the custom field             |
| `custom_title` | `string`         |     <i class="fa-square-x">:square-x:</i>     | Label used on the landing page       |
| `value`        | `string`         | <i class="fa-square-check">:square-check:</i> | Submitted value                      |
| `item_id`      | `string or null` |     <i class="fa-square-x">:square-x:</i>     | Internal reference to the form entry |

**`order_lines` array**

One entry per product ordered:

| Field           | Type              |                    Required                   | Description                                       |
| --------------- | ----------------- | :-------------------------------------------: | ------------------------------------------------- |
| `product_id`    | `string`          | <i class="fa-square-check">:square-check:</i> | ID of the product ordered                         |
| `product_name`  | `string`          | <i class="fa-square-check">:square-check:</i> | Name of the product variant                       |
| `variant_name`  | `string`          | <i class="fa-square-check">:square-check:</i> | Variant description (e.g., size, color)           |
| `quantity`      | `integer`         | <i class="fa-square-check">:square-check:</i> | Number of units ordered                           |
| `unit_price`    | `decimal`         | <i class="fa-square-check">:square-check:</i> | Price per unit                                    |
| `reduced_price` | `decimal or null` |     <i class="fa-square-x">:square-x:</i>     | Discounted price if applicable                    |
| `total_price`   | `decimal`         | <i class="fa-square-check">:square-check:</i> | Final price (unit × quantity or discounted total) |
| `sku`           | `string`          | <i class="fa-square-check">:square-check:</i> | Product SKU                                       |
| `shipping_id`   | `string or null`  |     <i class="fa-square-x">:square-x:</i>     | Product-specific shipping ID                      |

**`bundle_lines` array**

Empty array if no bundles were ordered.

**`shop_info` object**

| Field            | Type     |                    Required                   | Description       |
| ---------------- | -------- | :-------------------------------------------: | ----------------- |
| `shop_id`        | `string` | <i class="fa-square-check">:square-check:</i> | Unique shop ID    |
| `shop_name`      | `string` | <i class="fa-square-check">:square-check:</i> | Store name        |
| `shop_subdomain` | `string` | <i class="fa-square-check">:square-check:</i> | Store’s subdomain |

**`landing_page_info` object**

| Field                | Type     |                    Required                   | Description                     |
| -------------------- | -------- | :-------------------------------------------: | ------------------------------- |
| `landing_page_id`    | `string` | <i class="fa-square-check">:square-check:</i> | ID of the landing page          |
| `landing_page_title` | `string` | <i class="fa-square-check">:square-check:</i> | Title shown on the landing page |

***

### **Retry Behavior**

* If your endpoint responds with a non-`2xx` status or times out, we retry the request using **exponential backoff**:
  * 1st retry: \~5 seconds after failure
  * Subsequent retries: delay doubles each time, up to 5 minutes between attempts
* Each message is retried up to **5 times**.
* If all retries fail, the message is sent to a **Dead Letter Queue (DLQ)** and will not be redelivered automatically.

***

### Best Practices

* **Respond quickly** (<30s) with HTTP 2xx
* **Process asynchronously** — don't block on business logic
* **Verify signature** for authenticity
* **Use `event_id`** to ensure idempotency
* **Expect retries** and duplicate deliveries

***

### Support

For technical support, contact: <islam@ayor.ai> - <amine@ayor.ai> - <akram@ayor.ai><br>

***

*Last updated: August 7, 2025*
