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

# Asynchronous callbacks

> Supply a callback_url to receive docket query results pushed to your server, in addition to the synchronous response.

Any `GET /v2/case` request can include a `callback_url` parameter. When supplied, DocketLayer delivers the full query result to that URL asynchronously, in addition to returning the synchronous HTTP response.

This is useful for building event-driven pipelines: your agent or server receives the immediate response and a signed copy is pushed to your infrastructure without requiring you to poll.

## How it works

```
GET /v2/case?case_id=1:24-cv-01234&court_code=nysd&last_checked=...&callback_url=https://yourapp.com/webhooks/docketlayer
```

1. DocketLayer processes the query and returns the full response synchronously (200)
2. Independently, DocketLayer POSTs the same result to your `callback_url`
3. Your endpoint must respond 2xx to acknowledge receipt
4. If your endpoint does not respond 2xx, DocketLayer retries up to 7 times

The synchronous response is not delayed by the callback delivery.

## Callback payload

Your endpoint receives a POST with `Content-Type: application/json`:

```json theme={null}
{
  "payload": {
    "meta": { "...standard meta block..." },
    "case_id": "1:24-cv-01234",
    "court_code": "nysd",
    "case": { "...case data..." },
    "delta": { "...delta block if last_checked was supplied..." }
  },
  "webhook": {
    "version": "2.0.0",
    "event_type": "case_query_complete",
    "date_created": "2026-04-29T12:00:00Z",
    "deprecation_date": null
  }
}
```

The `payload` object is identical to the synchronous response body.

## Security headers

Every delivery includes these headers:

| Header                           | Description                                                         |
| -------------------------------- | ------------------------------------------------------------------- |
| `X-DocketLayer-Signature`        | HMAC-SHA256 of the raw request body: `sha256=<hex>`                 |
| `X-DocketLayer-Signature-Key-Id` | ID of the signing key used                                          |
| `X-DocketLayer-Timestamp`        | Unix timestamp of the delivery                                      |
| `Idempotency-Key`                | Stable UUIDv4 unique to this delivery — same on every retry attempt |

Always verify the signature before processing the payload. See the [HMAC verification guide](/guides/hmac-verification) for implementation.

## Retry schedule

DocketLayer retries failed deliveries (network errors, non-2xx responses) up to 7 times:

| Attempt | Delay after previous attempt |
| ------- | ---------------------------- |
| 2       | 3 minutes                    |
| 3       | 9 minutes                    |
| 4       | 27 minutes                   |
| 5       | \~1.4 hours                  |
| 6       | \~4 hours                    |
| 7       | \~12 hours                   |

After 7 failed attempts, the delivery is marked `failed` and no further retries occur. The total retry window is approximately 54 hours.

## Delivery history

All delivery attempts are logged and queryable via `GET /v2/wallet/deliveries`. Use it to diagnose failures and confirm delivery.

```bash theme={null}
# Check recent failed deliveries
curl "https://api.docketlayer.ai/v2/wallet/deliveries?status=failed"
```

## Receiving callbacks

Your endpoint should:

1. Respond 2xx immediately — do not wait for processing to complete before responding, or DocketLayer may time out and retry
2. Verify the `X-DocketLayer-Signature` header before trusting the payload
3. Use `Idempotency-Key` to deduplicate retries — your endpoint may receive the same delivery more than once

```python theme={null}
from flask import Flask, request, abort
import hmac, hashlib, time

app = Flask(__name__)
WEBHOOK_SECRET = os.environ["DOCKETLAYER_WEBHOOK_SECRET"]

@app.route("/webhooks/docketlayer", methods=["POST"])
def receive_callback():
    # Verify timestamp to prevent replay attacks
    timestamp = request.headers.get("X-DocketLayer-Timestamp", "0")
    if abs(time.time() - int(timestamp)) > 300:
        abort(400, "Timestamp out of range")

    # Verify signature
    raw_body = request.get_data()
    sig_header = request.headers.get("X-DocketLayer-Signature", "")
    expected = "sha256=" + hmac.new(
        WEBHOOK_SECRET.encode(), raw_body, hashlib.sha256
    ).hexdigest()
    if not hmac.compare_digest(expected, sig_header):
        abort(400, "Invalid signature")

    # Process payload
    data = request.json
    handle_docket_event(data["payload"])

    return "", 200
```

## Notes

* `callback_url` is supported on `GET /v2/case` only — not on `/v2/monitor` or batch
* Per-query `callback_url` values in `/v2/cases/batch` work: each query in the batch can specify its own `callback_url`
* Your callback endpoint must be reachable from the public internet — localhost URLs will not work in production
* DocketLayer does not validate or pre-check the `callback_url` before making the query
