> ## Documentation Index
> Fetch the complete documentation index at: https://docs.useproxy.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Webhooks

> Real-time event notifications

# Webhooks

Webhooks provide real-time notifications when events occur in your Proxy account. Configure endpoints to receive HTTP POST requests for events you care about.

## Setting Up Webhooks

### Create a Webhook Endpoint

```bash theme={"system"}
curl -X POST https://api.useproxy.ai/v1/webhooks \
  -H "Authorization: Bearer your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-app.com/webhooks/proxy",
    "events": ["transaction.created", "intent.matched"],
    "description": "Production webhook"
  }'
```

### Webhook Fields

| Field         | Type   | Description                         |
| ------------- | ------ | ----------------------------------- |
| `url`         | string | HTTPS endpoint to receive events    |
| `events`      | array  | List of event types to subscribe to |
| `description` | string | Human-readable description          |
| `status`      | string | `active` or `disabled`              |

## Event Types

### Transaction Events

| Event                  | Description              |
| ---------------------- | ------------------------ |
| `transaction.created`  | New transaction recorded |
| `transaction.settled`  | Transaction settled      |
| `transaction.declined` | Transaction was declined |

### Intent Events

| Event                     | Description                     |
| ------------------------- | ------------------------------- |
| `intent.created`          | New intent declared             |
| `intent.matched`          | Intent matched to transaction   |
| `intent.mismatched`       | Transaction didn't match intent |
| `intent.expired`          | Intent expired                  |
| `intent.pending_approval` | Intent awaiting approval        |

### Card Events

| Event          | Description     |
| -------------- | --------------- |
| `card.created` | New card issued |
| `card.frozen`  | Card was frozen |
| `card.closed`  | Card was closed |

## Webhook Payload

```json theme={"system"}
{
  "id": "evt_xxx",
  "type": "transaction.created",
  "createdAt": "2024-01-15T10:30:00Z",
  "data": {
    "transactionId": "txn_xxx",
    "cardId": "card_xxx",
    "amount": 5000,
    "merchant": "Amazon"
  }
}
```

## Signature Verification

All webhooks include a `Proxy-Signature` header for verification. The header format is:

```
Proxy-Signature: t=1706745600,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd
```

Where:

* `t` is the Unix timestamp (seconds) when the webhook was sent
* `v1` is the HMAC-SHA256 signature

The signature is computed over `{timestamp}.{json_payload}` using your webhook secret.

### Node.js Example

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

function verifyWebhook(req, secret) {
  const signature = req.headers['proxy-signature'];
  const payload = JSON.stringify(req.body);

  // Parse the signature header
  const parts = signature.split(',');
  const timestamp = parts[0].split('=')[1];
  const receivedSig = parts[1].split('=')[1];

  // Compute expected signature
  const signedPayload = `${timestamp}.${payload}`;
  const expectedSig = crypto
    .createHmac('sha256', secret)
    .update(signedPayload)
    .digest('hex');

  // Compare signatures (use timing-safe comparison)
  return crypto.timingSafeEqual(
    Buffer.from(receivedSig),
    Buffer.from(expectedSig)
  );
}

// Express.js handler example
app.post('/webhooks/proxy', express.json(), (req, res) => {
  const secret = 'whsec_your_webhook_secret';

  if (!verifyWebhook(req, secret)) {
    return res.status(401).send('Invalid signature');
  }

  // Process the webhook
  const event = req.body;
  console.log('Received event:', event.type);

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

### Convex Example

```typescript theme={"system"}
import { httpAction } from "./_generated/server";

export const webhookHandler = httpAction(async (ctx, request) => {
  const signature = request.headers.get("proxy-signature");
  const body = await request.text();
  const secret = process.env.PROXY_WEBHOOK_SECRET!;

  // Parse signature
  const parts = signature?.split(',') || [];
  const timestamp = parts[0]?.split('=')[1];
  const receivedSig = parts[1]?.split('=')[1];

  // Verify signature
  const signedPayload = `${timestamp}.${body}`;
  const encoder = new TextEncoder();
  const key = await crypto.subtle.importKey(
    "raw",
    encoder.encode(secret),
    { name: "HMAC", hash: "SHA-256" },
    false,
    ["sign"]
  );
  const sig = await crypto.subtle.sign("HMAC", key, encoder.encode(signedPayload));
  const expectedSig = Array.from(new Uint8Array(sig))
    .map(b => b.toString(16).padStart(2, '0'))
    .join('');

  if (receivedSig !== expectedSig) {
    return new Response("Invalid signature", { status: 401 });
  }

  // Process webhook
  const event = JSON.parse(body);
  console.log("Received:", event.type);

  return new Response("OK", { status: 200 });
});
```

<Warning>
  Always verify webhook signatures before processing events. This ensures the request came from Proxy and hasn't been tampered with.
</Warning>

## Retry Policy

Failed webhook deliveries are retried with exponential backoff:

| Attempt | Delay      |
| ------- | ---------- |
| 1       | Immediate  |
| 2       | 5 minutes  |
| 3       | 30 minutes |
| 4       | 2 hours    |
| 5       | 24 hours   |

After 5 failed attempts, the webhook is marked as failed and requires manual retry.

## Managing Webhooks

### List Webhooks

```bash theme={"system"}
curl https://api.useproxy.ai/v1/webhooks \
  -H "Authorization: Bearer your_api_key"
```

### Update a Webhook

```bash theme={"system"}
curl -X PATCH https://api.useproxy.ai/v1/webhooks/wh_xxx \
  -H "Authorization: Bearer your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "events": ["transaction.created", "transaction.declined"]
  }'
```

### Delete a Webhook

```bash theme={"system"}
curl -X DELETE https://api.useproxy.ai/v1/webhooks/wh_xxx \
  -H "Authorization: Bearer your_api_key"
```

## Next Steps

<CardGroup cols={2}>
  <Card title="API Reference" icon="code" href="/api-reference/introduction">
    Full API documentation
  </Card>

  <Card title="Quickstart" icon="rocket" href="/quickstart">
    Get started quickly
  </Card>
</CardGroup>
