Receive Async Results Automatically
Webhooks automatically deliver async operation results to your server. Use webhooks instead of polling to receive real-time notifications.
import hmacimport hashlibfrom flask import Flask, request, jsonifyapp = Flask(__name__)WEBHOOK_SECRET = "your_webhook_secret"def verify_signature(body: bytes, signature: str) -> bool: expected = hmac.new( WEBHOOK_SECRET.encode(), body, hashlib.sha256 ).hexdigest() return hmac.compare_digest(f"sha256={expected}", signature)@app.post("/webhook")def handle_webhook(): signature = request.headers.get("X-Webhook-Signature", "") if not verify_signature(request.get_data(), signature): return jsonify({"error": "Invalid signature"}), 401 payload = request.get_json() if payload["event"] == "job.completed": print(f"Job {payload['job_id']} completed!") print(f"Result: {payload['result']}") elif payload["event"] == "job.failed": print(f"Job {payload['job_id']} failed: {payload.get('error')}") return jsonify({"received": True}), 200A webhook is a notification mechanism that sends an HTTP POST request to your server when an event occurs. In ProxyTurk, when an async job (scrape, parse, serp) completes or fails, the result is sent to the URL you specified.
Advantages: - No polling needed (fewer requests, less resource usage) - Real-time notifications (instant results when the job finishes) - Fire-and-forget pattern (send the request, receive the result via webhook)
You can use webhooks in two ways:
1. Per-request: Send a webhook_url parameter with each API request 2. Dashboard: Define a global webhook URL (for all async jobs)
Your webhook URL must be HTTPS and publicly accessible. Localhost will not work (use ngrok or a similar tunnel for development).
Two event types are available:
- job.completed: When a job completes successfully. The result field in the payload contains the data. - job.failed: When a job fails. The error field in the payload contains error details.
The webhook POST request body is in JSON format:
{ "event": "job.completed", "job_id": "job_abc123", "status": "completed", "endpoint": "scrape", "result": { ... }, "meta": { "processing_time_ms": 823, "credits_used": 1, "created_at": "2026-08-12T15:30:00Z", "completed_at": "2026-08-12T15:30:01Z" } }
Headers: - Content-Type: application/json - X-Webhook-Signature: sha256=<HMAC-SHA256 signature> - X-Webhook-ID: Unique delivery ID (for idempotency)
Every webhook request is signed with the X-Webhook-Signature header. Verify this signature to ensure the request genuinely comes from ProxyTurk.
Signature format: sha256=<hex-encoded HMAC-SHA256> Key: Your webhook secret from the Dashboard Message: Request body (raw bytes)
If webhook delivery fails (non-2xx HTTP response or timeout), it is retried with exponential backoff:
- 1st attempt: Immediately - 2nd attempt: 30 seconds later - 3rd attempt: 2 minutes later - 4th attempt: 10 minutes later - 5th attempt: 1 hour later
A total of 5 attempts are made. If all fail, the webhook is abandoned. You can always retrieve the result via GET /v1/jobs/{id}.
Webhook not arriving: - Ensure your URL is HTTPS and publicly accessible - Check your firewall settings - Review webhook logs in the Dashboard
Signature verification failing: - Use the raw body (unparsed JSON) - Make sure you are using the correct webhook secret - Encoding issue: Use UTF-8
Duplicate webhooks: - Use the X-Webhook-ID header for idempotency - Store processed webhook IDs in your database
Questions about webhooks
No, your webhook URL must be accessible over the internet. For development, you can use ngrok, localtunnel, or Cloudflare Tunnel.
Your server must respond with an HTTP 2xx status within 30 seconds. Otherwise, it is considered a timeout and a retry will be attempted.
You can view incoming webhooks in real-time using webhook.site or requestbin.com. For development, you can expose your localhost with ngrok.