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

# Webhooks

> Receive real-time notifications for bureau submission status changes

Cove sends HTTP POST requests to your configured `webhook_url` when bureau submission statuses change.

## Event types

| Event                  | When Fired                                  | Key Data Fields                                               |
| ---------------------- | ------------------------------------------- | ------------------------------------------------------------- |
| `submission.pending`   | Metro 2 file generated, queued for delivery | `tradeline_id`, `bureau`, `submission_date`                   |
| `submission.submitted` | File uploaded to bureau via SFTP            | `tradeline_id`, `bureau`, `submission_date`                   |
| `submission.accepted`  | Bureau confirmed acceptance                 | `tradeline_id`, `bureau`, `response_code`, `response_message` |
| `submission.rejected`  | Bureau rejected the record                  | `tradeline_id`, `bureau`, `response_code`, `response_message` |
| `tradeline.updated`    | Tradeline status changed                    | `tradeline_id`, `changes`                                     |

## Payload format

```json theme={null}
{
  "id": "550e8400-e29b-41d4-a716-446655440099",
  "event": "submission.accepted",
  "created_at": "2026-02-06T14:30:00Z",
  "data": {
    "tradeline_id": "660e8400-e29b-41d4-a716-446655440001",
    "bureau": "equifax",
    "submission_date": "2026-02-05",
    "status": "accepted",
    "response_code": "00",
    "response_message": "Record accepted successfully"
  }
}
```

## Headers

Every webhook POST includes these headers:

| Header             | Value                                    |
| ------------------ | ---------------------------------------- |
| `Content-Type`     | `application/json`                       |
| `X-Cove-Signature` | `sha256=<HMAC-SHA256 hex digest>`        |
| `X-Cove-Event`     | Event type (e.g., `submission.accepted`) |
| `X-Cove-Delivery`  | Unique delivery UUID                     |

## Signature verification

The `X-Cove-Signature` header contains an HMAC-SHA256 digest of the raw request body, signed with your `webhook_secret`.

<CodeGroup>
  ```javascript Node.js theme={null}
  const crypto = require('crypto');

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

  // In your webhook handler:
  const rawBody = req.body; // raw string, not parsed JSON
  const signature = req.headers['x-cove-signature'];
  if (!verifyWebhook(rawBody, signature, process.env.WEBHOOK_SECRET)) {
    return res.status(401).send('Invalid signature');
  }
  ```

  ```python Python theme={null}
  import hmac
  import hashlib

  def verify_webhook(body: bytes, signature: str, secret: str) -> bool:
      expected = 'sha256=' + hmac.new(
          secret.encode(), body, hashlib.sha256
      ).hexdigest()
      return hmac.compare_digest(signature, expected)

  # In your webhook handler:
  raw_body = request.get_data()
  signature = request.headers.get('X-Cove-Signature')
  if not verify_webhook(raw_body, signature, os.environ['WEBHOOK_SECRET']):
      return 'Invalid signature', 401
  ```
</CodeGroup>

## Retry behavior

| Attempt | Delay      | Notes                  |
| ------- | ---------- | ---------------------- |
| 1       | Immediate  | First delivery attempt |
| 2       | 1 minute   | After first failure    |
| 3       | 10 minutes | After second failure   |
| 4       | 1 hour     | Final attempt          |

* Each attempt has a **10-second timeout**.
* After all retries are exhausted, the event is marked as `failed`.

<Tip>**Fallback**: Poll `GET /submissions` to check status if webhooks are missed.</Tip>

## Best practices

* **Return 2xx quickly** — process webhook data asynchronously. The 10-second timeout is strict.
* **Handle duplicates** — webhooks may be delivered more than once. Use the `id` field for idempotency.
* **Use `GET /submissions` for reconciliation** — don't rely solely on webhooks for critical business logic.
