Skip to main content

Overview

Webhooks allow you to receive real-time HTTP notifications when your inference jobs change status, eliminating the need to poll the /request-status endpoint.
Webhooks are sent as POST requests to your specified URL with a JSON payload and security headers for verification.

Configuration

Global Webhook URL

Configure a global webhook URL in your account settings. All jobs will send notifications to this URL unless overridden.

Per-Request Override

You can override the global webhook URL on any job request by including the webhook_url parameter:
{
  "prompt": "a beautiful sunset over mountains",
  "model": "flux-schnell",
  "webhook_url": "https://your-server.com/webhooks/deapi"
}
Only HTTPS URLs are accepted. HTTP URLs will be rejected for security.

Events

Webhooks are sent on the following status transitions:
EventTriggerDescription
job.processingpending → processingJob assigned to a worker, processing started
job.completedprocessing → doneJob completed successfully, results available
job.failedprocessing → errorJob failed during processing

Request Format

Headers

All webhook requests include these headers:
HeaderDescriptionExample
X-DeAPI-SignatureHMAC-SHA256 signature for verificationsha256=5d41402abc4b2a76b9719d911017c592...
X-DeAPI-TimestampUnix timestamp when webhook was sent1705315800
X-DeAPI-EventEvent type that triggered the webhookjob.completed
X-DeAPI-Delivery-IdUnique identifier for this delivery550e8400-e29b-41d4-a716-446655440001
Content-TypeAlways application/jsonapplication/json
User-AgentIdentifies the senderDeAPI-Webhook/1.0

Payload Structure

Sent when a worker starts processing your job.
{
  "event": "job.processing",
  "delivery_id": "550e8400-e29b-41d4-a716-446655440000",
  "timestamp": "2024-01-15T10:30:00.000Z",
  "data": {
    "job_request_id": "123e4567-e89b-12d3-a456-426614174000",
    "status": "processing",
    "previous_status": "pending",
    "job_type": "txt2img",
    "started_at": "2024-01-15T10:30:00.000Z"
  }
}
FieldTypeDescription
data.job_request_idstring (UUID)Your job’s unique identifier
data.statusstringCurrent status: processing
data.previous_statusstringPrevious status: pending
data.job_typestringType of job (e.g., txt2img, vid2txt)
data.started_atstring (ISO 8601)When processing began

Security

Signature Verification

Every webhook includes an HMAC-SHA256 signature in the X-DeAPI-Signature header. Always verify this signature to ensure the request came from deAPI. Signature format: sha256=<hex-encoded-hmac> How to verify:
  1. Get the timestamp from X-DeAPI-Timestamp header
  2. Get the raw JSON body (don’t parse it first)
  3. Concatenate: timestamp + "." + raw_body
  4. Calculate HMAC-SHA256 using your webhook secret
  5. Compare with the signature (use timing-safe comparison)
const crypto = require('crypto');

function verifyWebhook(req, secret) {
  const signature = req.headers['x-deapi-signature'];
  const timestamp = req.headers['x-deapi-timestamp'];
  const body = req.body.toString(); // Raw request body as string

  // Check timestamp is within 5 minutes
  const now = Math.floor(Date.now() / 1000);
  if (Math.abs(now - parseInt(timestamp)) > 300) {
    return false; // Reject old requests (replay attack prevention)
  }

  // Calculate expected signature
  const message = `${timestamp}.${body}`;
  const expected = 'sha256=' + crypto
    .createHmac('sha256', secret)
    .update(message)
    .digest('hex');

  // Timing-safe comparison
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expected)
  );
}

Best Practices

Always verify signatures

Never process webhooks without verifying the HMAC signature first.

Check timestamps

Reject webhooks with timestamps older than 5 minutes to prevent replay attacks.

Use HTTPS

Only configure HTTPS endpoints. HTTP is rejected automatically.

Handle idempotency

Use delivery_id to detect and handle duplicate deliveries.

Retry Policy

If your endpoint fails to respond with a 2xx status code, we’ll retry delivery with exponential backoff:
AttemptDelayCumulative Time
1Immediate0
21 minute1 min
32 minutes3 min
45 minutes8 min
510 minutes18 min
630 minutes48 min
71 hour1h 48min
83 hours4h 48min
96 hours10h 48min
1012 hours22h 48min
After 10 failed attempts (~24 hours), the webhook is marked as failed.
Circuit Breaker: After 10 consecutive failed deliveries across any webhooks for your account, webhooks are automatically disabled. Re-enable them in your account settings after fixing your endpoint.

Response Requirements

Your endpoint should:
  • Return a 2xx status code (200-299) within 10 seconds
  • Not follow redirects (3xx responses are treated as failures)
  • Process the webhook asynchronously if needed (respond quickly, process later)
// Example: Express.js endpoint
app.post('/webhooks/deapi', express.raw({ type: 'application/json' }), (req, res) => {
  // Verify signature first
  if (!verifyWebhook(req, process.env.DEAPI_WEBHOOK_SECRET)) {
    return res.status(401).send('Invalid signature');
  }

  const event = JSON.parse(req.body);

  // Respond immediately
  res.status(200).send('OK');

  // Process asynchronously
  processWebhookAsync(event);
});

Testing

Use webhook.site to test webhooks during development:
  1. Get a unique URL from webhook.site
  2. Configure it as your webhook URL (per-request or global)
  3. Submit a job and watch the webhooks arrive
  4. Verify headers and payloads match the expected format
You can also use tools like ngrok to expose your local development server to receive webhooks.