Skip to main content

Overview

Instead of polling for completion, register a webhook URL to receive a POST request when your document finishes processing.

Setup

Pass webhook_url when uploading a document:
curl -X POST https://api.okra.app/v1/documents/doc-abc123/upload-url \
  -H "Authorization: Bearer okra_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/report.pdf",
    "webhook_url": "https://your-app.com/webhooks/okrapdf"
  }'

Webhook payload

When the document completes, OkraPDF sends a POST request to your URL:
{
  "event": "document.completed",
  "document_id": "doc-abc123",
  "status": "completed",
  "file_name": "report.pdf",
  "total_pages": 12,
  "timestamp": "2025-01-15T10:30:00Z"
}

Webhook handler example

from flask import Flask, request, jsonify
import requests

app = Flask(__name__)

@app.route("/webhooks/okrapdf", methods=["POST"])
def handle_webhook():
    payload = request.json
    doc_id = payload["document_id"]

    if payload["status"] == "completed":
        # Fetch the markdown
        md = requests.get(
            f"https://api.okra.app/v1/documents/{doc_id}/full.md",
        ).text
        process_document(md)

    return jsonify({"received": True}), 200

Retry behavior

  • OkraPDF retries failed webhook deliveries up to 3 times
  • Retries use exponential backoff (5s, 30s, 5min)
  • Your endpoint must return a 2xx status to acknowledge receipt
  • Non-2xx or timeout (30s) triggers a retry

Best practices

  1. Return 200 quickly - process the webhook payload asynchronously
  2. Use HTTPS - webhook URLs must use HTTPS in production
  3. Verify the payload - check that the document_id exists in your system
  4. Handle duplicates - webhooks may be delivered more than once