Skip to main content
Any endpoint that accepts sync=false will return immediately with a task_id and process in the background. When complete, the result is available via polling or delivered to your webhook URL.

Async processing

from thedriveai import TheDriveAI

client = TheDriveAI(api_key="tda_live_...")

# Submit async
task = client.extract_async(
    file="large_report.pdf",
    schema={"title": {"type": "string", "description": "Document title"}},
    webhook_url="https://your-app.com/webhooks/thedrive",
)
print(task.task_id)  # "task_a1b2c3d4e5f6"

# Or poll for result
result = client.wait_for_task(task.task_id, timeout=300)
print(result.status)  # "completed"
print(result.result)  # The extraction result

Webhook payload

When the task completes, we POST the result to your webhook_url:
{
  "task_id": "task_a1b2c3d4e5f6",
  "status": "completed",
  "created_at": "2025-06-15T10:30:00Z",
  "completed_at": "2025-06-15T10:30:12Z",
  "credits_used": 7,
  "result": {
    "success": true,
    "data": {"title": "Q3 Financial Report"},
    "confidence": {"title": 0.96},
    ...
  }
}

Verifying webhooks

Every webhook includes two security headers:
HeaderPurpose
X-TDA-SignatureHMAC-SHA256 signature of the raw request body
X-TDA-Delivery-IDUnique delivery ID for deduplication
Verify the signature to ensure the payload is authentic and hasn’t been tampered with:
import hmac
import hashlib

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

# In your webhook handler (e.g. Flask/FastAPI):
@app.post("/webhooks/thedrive")
async def handle_webhook(request: Request):
    body = await request.body()
    signature = request.headers.get("X-TDA-Signature", "")

    if not verify_webhook(body, signature, "your-webhook-signing-secret"):
        raise HTTPException(status_code=401, detail="Invalid signature")

    payload = await request.json()
    # Process the result...
Always verify the X-TDA-Signature header before trusting a webhook payload. Without verification, anyone who discovers your webhook URL could send forged payloads.

Retry policy

Failed webhook deliveries are retried automatically:
PhaseTiming
Inline retries3 attempts with exponential backoff (immediate, 2s, 4s)
Background retries1min, 5min, 15min, 30min, 1hr, 2hr, 4hr
Total8 attempts over ~8 hours
  • 4xx responses are treated as permanent failures (not retried)
  • 5xx responses and timeouts are retried
  • Your endpoint should return 200 to acknowledge receipt

Checking delivery status

If you didn’t receive a webhook, check the delivery log:
curl https://dev.thedrive.ai/api/v1/jobs/task_a1b2c3d4e5f6/deliveries \
  -H "X-API-Key: tda_live_..."
{
  "task_id": "task_a1b2c3d4e5f6",
  "deliveries": [
    {
      "id": "whd_a1b2c3d4e5f6g7h8",
      "status": "delivered",
      "status_code": 200,
      "attempts": 1,
      "created_at": "2025-06-15T10:30:12Z",
      "delivered_at": "2025-06-15T10:30:13Z"
    }
  ]
}
Delivery statuses:
  • pending — Not yet attempted
  • delivered — Successfully received (2xx response)
  • failed — Will be retried
  • dead — Exhausted all retry attempts or permanent 4xx failure

Deduplication

Use the X-TDA-Delivery-ID header to deduplicate retries. If your server crashes after processing but before responding, the retry will carry the same delivery ID.
@app.post("/webhooks/thedrive")
async def handle_webhook(request: Request):
    delivery_id = request.headers.get("X-TDA-Delivery-ID")

    # Check if already processed
    if await db.exists("processed_webhooks", delivery_id):
        return {"ok": True}  # Already handled, just ACK

    # Process...
    await db.insert("processed_webhooks", {"id": delivery_id})
    return {"ok": True}