Skip to main content

Documentation Index

Fetch the complete documentation index at: https://www.edenai.co/docs/llms.txt

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

Webhooks let you receive results from async Universal AI jobs via HTTP callbacks instead of polling. When a job completes, Eden AI sends a signed POST request to the URL you provided.

How It Works

  1. Submit an async request with a webhook_receiver in the payload.
  2. Eden AI processes the job in the background.
  3. On completion, Eden AI sends a signed POST request to your webhook_receiver with the result.

Request Parameters

FieldTypeRequiredDescription
webhook_receiverstring (URL)noHTTPS URL that will receive the POST when the job completes or fails. Validated against SSRF.
user_webhook_parametersobjectnoFree-form JSON object echoed back as user_parameters in the webhook payload. Useful for correlating the callback to your own records.

Webhook Headers

Every webhook request Eden AI sends includes these headers:
HeaderExample valueDescription
Content-Typeapplication/jsonBody is always JSON.
User-AgentEdenAI/Ai-FeaturesIdentifies the sender.
X-Edenai-WebhooktrueFlag marking the request as an Eden AI webhook.
X-Edenai-Signaturea8f3... (hex)RSA PKCS1 v1.5 signature of the payload.
X-Edenai-Hash-AlgorithmSHA256Hash algorithm used to produce the signature.

Webhook Payload

{
  "event": "async_job_completed",
  "job_id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "success",
  "feature": "ocr",
  "subfeature": "ocr_async",
  "provider": "amazon",
  "model": null,
  "created_at": "2026-04-21T12:00:00+00:00",
  "finished_at": "2026-04-21T12:01:30+00:00",
  "output": { "raw_text": "..." },
  "user_parameters": { "internal_ref": "order-42" }
}
FieldTypeDescription
eventstringAlways "async_job_completed".
job_idstring (UUID)ID of the completed job.
status"success" | "fail"Final job status.
featurestringFeature name (e.g. "ocr", "audio").
subfeaturestringSubfeature name (e.g. "ocr_async").
providerstringProvider that produced the result.
modelstring | nullProvider-specific model, if any.
created_atstring (ISO 8601)When the job was created.
finished_atstring (ISO 8601)When the job finished.
outputobjectNormalized result. Present only on status: "success".
errorobject{ "message": "..." }. Present only on status: "fail".
original_responseanyRaw provider response. Only present when the request had show_original_response: true.
user_parametersobjectEcho of user_webhook_parameters. Absent if not set.

Signature Verification

Every webhook is signed with Eden AI’s RSA private key so you can verify it was not forged or tampered with in transit.
Ask Eden AI support for the webhook public key (webhook_rsa.pub.pem) and store it with your service configuration.
The signature is built as follows:
  1. The payload is serialized with canonical JSON (sorted keys, 2-space indent, UTF-8).
  2. sha256(canonical_json_bytes) is computed and its hex digest is taken.
  3. That hex digest is signed with RSA PKCS1 v1.5 / SHA-256.
  4. The hex-encoded signature is sent in X-Edenai-Signature.
To verify, reproduce the same canonical JSON before hashing — do not re-serialize with default formatting.

Example

Dependencies: pip install requests flask pycryptodome orjsonSending the request:
import requests

url = "https://api.edenai.run/v3/universal-ai/async"
headers = {
    "Authorization": "Bearer YOUR_API_KEY",
    "Content-Type": "application/json",
}
payload = {
    "model": "ocr/ocr_async/amazon",
    "input": {"file": "YOUR_FILE_UUID_OR_URL"},
    "webhook_receiver": "https://your-server.com/webhooks/edenai",
    "user_webhook_parameters": {"internal_ref": "order-42"},
}
response = requests.post(url, headers=headers, json=payload)
print(response.json())  # Contains the job ID
Receiving and verifying the webhook (Flask):
import hashlib
import orjson
from flask import Flask, request, abort, jsonify
from Crypto.Hash import SHA256
from Crypto.PublicKey import RSA
from Crypto.Signature import PKCS1_v1_5

app = Flask(__name__)

with open("edenai_webhook_rsa.pub.pem", "rb") as f:
    EDENAI_PUBLIC_KEY = RSA.import_key(f.read())


def verify_signature(raw_body: bytes, signature_hex: str) -> bool:
    payload = orjson.loads(raw_body)
    canonical = orjson.dumps(
        payload,
        option=orjson.OPT_INDENT_2 | orjson.OPT_SORT_KEYS,
    )
    hash_hex = hashlib.sha256(canonical).hexdigest()
    verifier = PKCS1_v1_5.new(EDENAI_PUBLIC_KEY)
    digest = SHA256.new(data=hash_hex.encode("utf-8"))
    try:
        return verifier.verify(digest, bytes.fromhex(signature_hex))
    except ValueError:
        return False


@app.route("/webhooks/edenai", methods=["POST"])
def handle_webhook():
    signature = request.headers.get("X-Edenai-Signature", "")
    if not verify_signature(request.get_data(), signature):
        abort(401, description="Invalid Eden AI webhook signature")

    payload = request.get_json()
    if payload["status"] == "success":
        print(f"Job {payload['job_id']} completed: {payload['output']}")
    else:
        print(f"Job {payload['job_id']} failed: {payload['error']['message']}")
    return jsonify({"received": True}), 200
Do not re-serialize the parsed JSON with defaults (e.g. JSON.stringify(obj) or json.dumps(obj) without sort_keys=True, indent=2) — any difference in spacing, key ordering, or unicode escaping will make the signature fail to verify.

Retry Behavior

Eden AI retries webhook delivery up to 3 times with exponential backoff between attempts (max delay 30 s) when the receiver returns a transient failure. Each attempt has a per-request timeout of 30 s.
OutcomeRetried?
HTTP 2xx
HTTP 4xxNo
HTTP 5xxYes
Per-request timeout (30 s)Yes
Connection / network errorYes
Keep your webhook handler idempotent — Eden AI may deliver the same job_id more than once if a retry races with a slow response from your server.

Webhook vs Polling

WebhooksPolling
How it worksEden AI pushes the result to your URLYou repeatedly call GET /v3/universal-ai/async/{job_id}
LatencyImmediate notification on completionDepends on polling interval
EfficiencyNo wasted requestsRequires repeated API calls
SetupRequires a publicly accessible endpointWorks from any client

Next Steps

Monitoring

Track async job results and API usage in the dashboard