> ## Documentation Index
> Fetch the complete documentation index at: https://developer.9squid.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Webhooks

Webhooks deliver real-time event notifications to your server whenever something happens on the platform — a deal status changes, a loan is approved, a trade settles. This recipe shows how to subscribe, verify delivery, and replay failed events.

## Overview

```
1. POST /webhooks/subscriptions          → create a subscription
2. GET  /webhooks/subscriptions          → list your subscriptions
3. GET  /webhooks/deliveries             → view delivery history
4. POST /webhooks/deliveries/:id/replay  → replay a failed delivery
5. DELETE /webhooks/subscriptions/:id   → remove a subscription
```

***

## Step 1 — Create a Subscription

Point the platform at your endpoint and specify which events to receive. If you omit `events`, you'll receive all event types.

```bash theme={null}
curl -X POST https://api.9squid.com/v1/api/webhooks/subscriptions \
  -H "Authorization: Bearer <your_token>" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-server.com/webhooks/9squid",
    "events": ["deal.status_changed", "loan.approved", "trade.settled"]
  }'
```

**Response**

```json theme={null}
{
  "success": true,
  "data": {
    "id": "clxsub001",
    "url": "https://your-server.com/webhooks/9squid",
    "events": ["deal.status_changed", "loan.approved", "trade.settled"],
    "secret": "whsec_abc123xyz",
    "created_at": "2026-04-15T10:00:00Z"
  }
}
```

> Save the `secret` — it is only shown once. Use it to verify webhook signatures on incoming requests.

***

## Available Events

| Event                 | Triggered when                                                   |
| --------------------- | ---------------------------------------------------------------- |
| `deal.status_changed` | A deal moves to a new status (e.g. `IN_REVIEW` → `QC_COMPLETED`) |
| `loan.approved`       | A loan deal is approved for securitization                       |
| `loan.rejected`       | A loan deal is rejected                                          |
| `trade.settled`       | An investor trade reaches settlement                             |
| `sc.completed`        | A Selection Criteria job finishes                                |
| `document.uploaded`   | A document is successfully uploaded to the deal room             |

***

## Step 2 — List Your Subscriptions

```bash theme={null}
curl https://api.9squid.com/v1/api/webhooks/subscriptions \
  -H "Authorization: Bearer <your_token>"
```

**Response**

```json theme={null}
{
  "success": true,
  "data": [
    {
      "id": "clxsub001",
      "url": "https://your-server.com/webhooks/9squid",
      "events": ["deal.status_changed", "loan.approved", "trade.settled"],
      "created_at": "2026-04-15T10:00:00Z"
    }
  ]
}
```

***

## Step 3 — View Delivery History

Check which events have been delivered and whether they succeeded.

```bash theme={null}
curl https://api.9squid.com/v1/api/webhooks/deliveries \
  -H "Authorization: Bearer <your_token>"
```

**Response**

```json theme={null}
{
  "success": true,
  "data": [
    {
      "id": "clxdlv001",
      "subscription_id": "clxsub001",
      "event": "deal.status_changed",
      "status": "DELIVERED",
      "http_status": 200,
      "attempts": 1,
      "created_at": "2026-04-15T11:00:00Z"
    },
    {
      "id": "clxdlv002",
      "subscription_id": "clxsub001",
      "event": "loan.approved",
      "status": "FAILED",
      "http_status": 503,
      "attempts": 3,
      "created_at": "2026-04-15T11:05:00Z"
    }
  ]
}
```

***

## Step 4 — Replay a Failed Delivery

If a delivery failed (your server was down, returned a non-2xx, etc.), you can trigger a replay:

```bash theme={null}
curl -X POST https://api.9squid.com/v1/api/webhooks/deliveries/clxdlv002/replay \
  -H "Authorization: Bearer <your_token>"
```

**Response**

```json theme={null}
{
  "success": true,
  "data": {
    "delivery_id": "clxdlv003",
    "status": "PENDING"
  }
}
```

A new delivery attempt is queued. Check delivery history after a moment to confirm the result.

***

## Step 5 — Remove a Subscription

```bash theme={null}
curl -X DELETE https://api.9squid.com/v1/api/webhooks/subscriptions/clxsub001 \
  -H "Authorization: Bearer <your_token>"
```

**Response**

```json theme={null}
{
  "success": true,
  "message": "Subscription removed"
}
```

***

## Verifying Webhook Signatures

Every webhook delivery includes an `X-9Squid-Signature` header. Verify it using the `secret` returned when you created the subscription to confirm the request is genuine.

```javascript theme={null}
const crypto = require('crypto');

function verifyWebhook(payload, signature, secret) {
  const expected = crypto
    .createHmac('sha256', secret)
    .update(payload)
    .digest('hex');
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(`sha256=${expected}`)
  );
}
```

Always reject requests where the signature does not match.

***

## Webhook Payload Shape

```json theme={null}
{
  "event": "deal.status_changed",
  "timestamp": "2026-04-15T11:00:00Z",
  "data": {
    "deal_id": "clx1a2b3c4d5e6f7g8h9",
    "previous_status": "IN_REVIEW",
    "current_status": "QC_COMPLETED"
  }
}
```

The `data` object shape varies by event type.

***

## What's Next

* [Create a Deal](/workflows/create-a-deal) — subscribe before submitting a deal to receive live status updates
* [Run Selection Criteria](/workflows/run-selection-criteria) — listen for `sc.completed` to know when results are ready
* [API Reference — Webhooks](/api-reference/webhooks/subscriptionscontroller_create) — full schema for all webhook endpoints
