Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.anyformat.ai/llms.txt

Use this file to discover all available pages before exploring further.

Webhooks eliminate the need for polling — your server gets an HTTP callback the moment a processing event fires.

Event Types

EventDescription
extraction.completedProcessing finished successfully, results are available
extraction.failedProcessing encountered an error
If you omit the events field when creating a webhook, it defaults to all supported events.

Requirements

  • HTTPS required: Webhook URLs must use HTTPS. HTTP URLs are rejected.
  • API version: Webhook endpoints require the v2 API (/v2/webhooks/).
  • Limit: Up to 50 active webhook subscriptions per organization.

How It Works

  1. Create a webhook with your HTTPS endpoint URL
  2. Save the secret from the creation response (it is only returned once)
  3. When processing completes or fails, your endpoint receives a POST request
  4. Verify the request signature using the secret

Payload Structure

Every webhook delivery sends a JSON POST request with this structure:
{
  "event": "extraction.completed",
  "timestamp": "2024-03-24T12:02:30.000Z",
  "data": {
    "extraction_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "status": "processed",
    "workflow_id": "550e8400-e29b-41d4-a716-446655440000",
    "processed_at": "2024-03-24T12:02:30.000Z"
  }
}
FieldTypeDescription
eventstringextraction.completed or extraction.failed
timestampstringISO 8601 timestamp of the event
data.extraction_idstringUUID of the extraction
data.statusstringprocessed (completed) or error (failed)
data.workflow_idstringUUID of the workflow used
data.processed_atstring or nullISO 8601 timestamp when processing finished, null on failure
For extraction.failed, the payload looks the same but with status: "error" and processed_at: null:
{
  "event": "extraction.failed",
  "timestamp": "2024-03-24T12:02:30.000Z",
  "data": {
    "extraction_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "status": "error",
    "workflow_id": "550e8400-e29b-41d4-a716-446655440000",
    "processed_at": null
  }
}

Delivery Headers

Each webhook request includes these headers:
HeaderDescription
Content-Typeapplication/json
X-Webhook-Signaturesha256={hex_digest} — HMAC-SHA256 signature for verification
X-Webhook-EventThe event type (extraction.completed or extraction.failed)
X-Webhook-Delivery-IdUnique UUID for this delivery attempt (useful for deduplication)
User-AgentAnyFormat-Webhooks/1.0

Signature Verification

Webhook payloads are signed using HMAC-SHA256. To verify a delivery:
  1. Read the raw request body (the JSON string exactly as received)
  2. Compute HMAC-SHA256(secret, body) using the secret from webhook creation
  3. Compare the result with the value after sha256= in the X-Webhook-Signature header
import hmac
import hashlib

def verify_webhook(payload_body: bytes, signature_header: str, secret: str) -> bool:
    expected = hmac.new(
        secret.encode(), payload_body, hashlib.sha256
    ).hexdigest()
    received = signature_header.removeprefix("sha256=")
    return hmac.compare_digest(expected, received)
Always use a constant-time comparison (hmac.compare_digest) to prevent timing attacks. Never use == to compare signatures.

Retry Policy

SettingValue
Max attempts3 (initial + 2 retries)
Delay between retries1 second (fixed)
Request timeout5 seconds per attempt
Connection timeout3 seconds
If all 3 attempts fail, the delivery is dropped and logged on our side. Webhook failures do not affect processing itself — delivery is best-effort.
To avoid missed events during outages, we recommend periodically listing your files with GET /v2/workflows/{workflow_id}/files/ and checking for any with status: "processed" or status: "error" that you haven’t handled.

Webhook Secret

When you create a webhook, the API returns a secret field (a 64-character hex string). This secret is only included in the creation response and is excluded from list responses. Store it securely.

Endpoints

MethodEndpointDescription
POST/v2/webhooks/Create a webhook
GET/v2/webhooks/List webhooks
DELETE/v2/webhooks/{id}/Delete a webhook