# Webhook API

The Webhook API allows you to receive real-time notifications when events occur in your Zaits account.

## Base URL

```
https://api.zaits.net/v1/webhooks
```

## Authentication

All requests require your API key in the Authorization header:

```http
Authorization: Bearer YOUR_API_KEY
```

***

## How Webhooks Work

1. **Register an endpoint** - Provide a URL on your server to receive events
2. **Select events** - Choose which events you want to be notified about
3. **Receive notifications** - We'll send POST requests to your endpoint when events occur
4. **Verify & process** - Verify the webhook signature and process the event

***

## Create Webhook Endpoint

Register a new webhook endpoint to receive notifications.

### Endpoint

```http
POST /v1/webhooks/endpoints
```

### Parameters

| Parameter     | Type    | Required | Description                                |
| ------------- | ------- | -------- | ------------------------------------------ |
| `url`         | string  | Yes      | Your webhook endpoint URL (must be HTTPS)  |
| `events`      | array   | Yes      | Array of event types to subscribe to       |
| `description` | string  | No       | Description of the endpoint                |
| `active`      | boolean | No       | Whether endpoint is active (default: true) |

### Request Example

{% tabs %}
{% tab title="cURL" %}

```bash
curl -X POST https://api.zaits.net/v1/webhooks/endpoints \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-app.com/webhooks/zaits",
    "events": ["document.signed", "face.verified", "ocr.completed"],
    "description": "Main production webhook",
    "active": true
  }'
```

{% endtab %}

{% tab title="JavaScript" %}

```javascript
const response = await fetch("https://api.zaits.net/v1/webhooks/endpoints", {
  method: "POST",
  headers: {
    Authorization: "Bearer YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    url: "https://your-app.com/webhooks/zaits",
    events: ["document.signed", "face.verified", "ocr.completed"],
    description: "Main production webhook",
    active: true,
  }),
});

const result = await response.json();
```

{% endtab %}

{% tab title="Python" %}

```python
import requests

response = requests.post(
    'https://api.zaits.net/v1/webhooks/endpoints',
    headers={
        'Authorization': 'Bearer YOUR_API_KEY',
        'Content-Type': 'application/json'
    },
    json={
        'url': 'https://your-app.com/webhooks/zaits',
        'events': ['document.signed', 'face.verified', 'ocr.completed'],
        'description': 'Main production webhook',
        'active': True
    }
)

result = response.json()
```

{% endtab %}
{% endtabs %}

### Response

```json
{
  "success": true,
  "data": {
    "id": "we_abc123xyz",
    "url": "https://your-app.com/webhooks/zaits",
    "events": ["document.signed", "face.verified", "ocr.completed"],
    "description": "Main production webhook",
    "secret": "whsec_1234567890abcdef",
    "active": true,
    "created_at": "2024-01-15T10:00:00Z"
  }
}
```

{% hint style="warning" %}
**Important:** Save the `secret` value! You'll need it to verify webhook signatures. It's only shown once when creating the endpoint.
{% endhint %}

***

## List Webhook Endpoints

Get all your configured webhook endpoints.

### Endpoint

```http
GET /v1/webhooks/endpoints
```

### Query Parameters

| Parameter  | Type    | Description                  |
| ---------- | ------- | ---------------------------- |
| `active`   | boolean | Filter by active status      |
| `page`     | number  | Page number (default: 1)     |
| `per_page` | number  | Items per page (default: 25) |

### Request Example

```bash
curl -X GET "https://api.zaits.net/v1/webhooks/endpoints?active=true" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

### Response

```json
{
  "success": true,
  "data": [
    {
      "id": "we_abc123xyz",
      "url": "https://your-app.com/webhooks/zaits",
      "events": ["document.signed", "face.verified"],
      "description": "Main production webhook",
      "active": true,
      "created_at": "2024-01-15T10:00:00Z",
      "last_delivery": "2024-01-15T14:30:00Z",
      "success_rate": 0.98
    }
  ],
  "pagination": {
    "page": 1,
    "per_page": 25,
    "total": 3
  }
}
```

***

## Update Webhook Endpoint

Update an existing webhook endpoint configuration.

### Endpoint

```http
PUT /v1/webhooks/endpoints/{endpoint_id}
```

### Parameters

| Parameter     | Type    | Required | Description                 |
| ------------- | ------- | -------- | --------------------------- |
| `url`         | string  | No       | New webhook URL             |
| `events`      | array   | No       | Updated event subscriptions |
| `description` | string  | No       | Updated description         |
| `active`      | boolean | No       | Enable/disable endpoint     |

### Request Example

```bash
curl -X PUT https://api.zaits.net/v1/webhooks/endpoints/we_abc123xyz \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "events": ["document.signed", "document.expired", "face.verified"],
    "active": true
  }'
```

### Response

```json
{
  "success": true,
  "data": {
    "id": "we_abc123xyz",
    "url": "https://your-app.com/webhooks/zaits",
    "events": ["document.signed", "document.expired", "face.verified"],
    "active": true,
    "updated_at": "2024-01-15T15:00:00Z"
  }
}
```

***

## Delete Webhook Endpoint

Remove a webhook endpoint.

### Endpoint

```http
DELETE /v1/webhooks/endpoints/{endpoint_id}
```

### Request Example

```bash
curl -X DELETE https://api.zaits.net/v1/webhooks/endpoints/we_abc123xyz \
  -H "Authorization: Bearer YOUR_API_KEY"
```

### Response

```json
{
  "success": true,
  "data": {
    "message": "Webhook endpoint deleted successfully",
    "endpoint_id": "we_abc123xyz"
  }
}
```

***

## Test Webhook Endpoint

Send a test event to verify your endpoint is working.

### Endpoint

```http
POST /v1/webhooks/endpoints/{endpoint_id}/test
```

### Parameters

| Parameter    | Type   | Required | Description                          |
| ------------ | ------ | -------- | ------------------------------------ |
| `event_type` | string | No       | Event type to test (default: "test") |

### Request Example

```bash
curl -X POST https://api.zaits.net/v1/webhooks/endpoints/we_abc123xyz/test \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "event_type": "document.signed"
  }'
```

### Response

```json
{
  "success": true,
  "data": {
    "test_sent": true,
    "response_status": 200,
    "response_time": 145,
    "response_body": "OK"
  }
}
```

***

## Get Webhook Deliveries

View the delivery history for a webhook endpoint.

### Endpoint

```http
GET /v1/webhooks/endpoints/{endpoint_id}/deliveries
```

### Query Parameters

| Parameter    | Type   | Description                           |
| ------------ | ------ | ------------------------------------- |
| `status`     | string | Filter by status: `success`, `failed` |
| `event_type` | string | Filter by event type                  |
| `page`       | number | Page number                           |
| `per_page`   | number | Items per page                        |

### Request Example

```bash
curl -X GET "https://api.zaits.net/v1/webhooks/endpoints/we_abc123xyz/deliveries?status=failed" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

### Response

```json
{
  "success": true,
  "data": [
    {
      "id": "del_xyz789",
      "event_id": "evt_abc123",
      "event_type": "document.signed",
      "status": "failed",
      "attempts": 3,
      "response_status": 500,
      "response_time": 2045,
      "error_message": "Internal server error",
      "created_at": "2024-01-15T14:30:00Z",
      "last_attempt": "2024-01-15T14:35:00Z"
    }
  ],
  "pagination": {
    "page": 1,
    "per_page": 25,
    "total": 12
  }
}
```

***

## Available Events

Get a list of all webhook event types you can subscribe to.

### Endpoint

```http
GET /v1/webhooks/events
```

### Request Example

```bash
curl -X GET https://api.zaits.net/v1/webhooks/events \
  -H "Authorization: Bearer YOUR_API_KEY"
```

### Response

```json
{
  "success": true,
  "data": {
    "events": [
      {
        "name": "document.signed",
        "description": "Document has been signed by a signer",
        "category": "signing"
      },
      {
        "name": "document.completed",
        "description": "All signers have signed the document",
        "category": "signing"
      },
      {
        "name": "document.expired",
        "description": "Document signing period has expired",
        "category": "signing"
      },
      {
        "name": "face.verified",
        "description": "Face verification completed",
        "category": "face"
      },
      {
        "name": "face.liveness.detected",
        "description": "Liveness detection completed",
        "category": "face"
      },
      {
        "name": "ocr.completed",
        "description": "OCR processing completed",
        "category": "ocr"
      },
      {
        "name": "ocr.id.extracted",
        "description": "ID card data extracted",
        "category": "ocr"
      },
      {
        "name": "user.credits.low",
        "description": "User credits below threshold",
        "category": "account"
      },
      {
        "name": "api.rate.limited",
        "description": "API rate limit exceeded",
        "category": "system"
      }
    ]
  }
}
```

***

## Webhook Payload Format

All webhook events are sent as POST requests with this format:

### Headers

```http
Content-Type: application/json
X-Zaits-Signature: sha256=1234567890abcdef...
X-Zaits-Event: document.signed
X-Zaits-Delivery: del_xyz789
```

### Body

```json
{
  "id": "evt_abc123xyz",
  "type": "document.signed",
  "created": 1642251600,
  "data": {
    "document_id": "doc_abc123",
    "signer": {
      "email": "john@example.com",
      "name": "John Doe"
    },
    "signed_at": "2024-01-15T14:30:00Z",
    "ip_address": "192.168.1.1"
  }
}
```

***

## Webhook Security

### Verifying Webhook Signatures

To ensure webhooks are from Zaits, verify the signature:

{% tabs %}
{% tab title="Node.js" %}

```javascript
const crypto = require("crypto");

function verifyWebhookSignature(payload, signature, secret) {
  const expectedSignature = crypto
    .createHmac("sha256", secret)
    .update(payload)
    .digest("hex");

  return `sha256=${expectedSignature}` === signature;
}

// Express.js example
app.post(
  "/webhooks/zaits",
  express.raw({ type: "application/json" }),
  (req, res) => {
    const signature = req.headers["x-zaits-signature"];
    const secret = "whsec_1234567890abcdef"; // Your webhook secret

    if (!verifyWebhookSignature(req.body, signature, secret)) {
      return res.status(401).send("Invalid signature");
    }

    const event = JSON.parse(req.body);

    // Process the event
    switch (event.type) {
      case "document.signed":
        handleDocumentSigned(event.data);
        break;
      // ... handle other events
    }

    res.status(200).send("OK");
  }
);
```

{% endtab %}

{% tab title="Python" %}

```python
import hmac
import hashlib
from flask import Flask, request, abort

app = Flask(__name__)

def verify_webhook_signature(payload, signature, secret):
    expected_signature = hmac.new(
        secret.encode('utf-8'),
        payload,
        hashlib.sha256
    ).hexdigest()

    return f'sha256={expected_signature}' == signature

@app.route('/webhooks/zaits', methods=['POST'])
def webhook():
    signature = request.headers.get('X-Zaits-Signature')
    secret = 'whsec_1234567890abcdef'  # Your webhook secret

    if not verify_webhook_signature(request.data, signature, secret):
        abort(401)

    event = request.json

    # Process the event
    if event['type'] == 'document.signed':
        handle_document_signed(event['data'])
    # ... handle other events

    return 'OK', 200
```

{% endtab %}

{% tab title="PHP" %}

```php
<?php
function verifyWebhookSignature($payload, $signature, $secret) {
    $expectedSignature = 'sha256=' . hash_hmac('sha256', $payload, $secret);
    return hash_equals($expectedSignature, $signature);
}

// Get the raw POST body
$payload = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_ZAITS_SIGNATURE'];
$secret = 'whsec_1234567890abcdef'; // Your webhook secret

if (!verifyWebhookSignature($payload, $signature, $secret)) {
    http_response_code(401);
    die('Invalid signature');
}

$event = json_decode($payload, true);

// Process the event
switch($event['type']) {
    case 'document.signed':
        handleDocumentSigned($event['data']);
        break;
    // ... handle other events
}

http_response_code(200);
echo 'OK';
?>
```

{% endtab %}
{% endtabs %}

***

## Webhook Retry Policy

If your endpoint fails to respond successfully:

1. **Initial attempt** - Sent immediately when event occurs
2. **First retry** - After 1 minute
3. **Second retry** - After 5 minutes
4. **Third retry** - After 30 minutes
5. **Final retry** - After 2 hours

After 5 failed attempts, the webhook delivery is marked as failed.

### Successful Response

Your endpoint should return a 2xx status code (200-299) within 10 seconds.

### Failed Response

Any of these constitute a failed delivery:

* Non-2xx status code
* Timeout (>10 seconds)
* Connection error
* Invalid SSL certificate

***

## Best Practices

### Endpoint Implementation

* **Return quickly** - Process webhooks asynchronously
* **Idempotency** - Handle duplicate events gracefully
* **Order** - Don't assume events arrive in order
* **Verification** - Always verify webhook signatures
* **HTTPS only** - Use SSL/TLS for security

### Error Handling

* Return 200 OK immediately, process async
* Log all webhook events for debugging
* Implement retry logic for your own processing
* Monitor webhook delivery success rate

### Security

* Keep webhook secrets secure
* Rotate secrets periodically
* Whitelist Zaits IP addresses if possible
* Validate event data before processing

***

**Next:** [Usage & Analytics API](/api/api-reference/usage-analytics.md)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## 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://zaits.gitbook.io/api/api-reference/webhooks.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.
