Skip to main content

Retry policy

DPay Web EID uses retries to provide reliable webhook delivery. This guide explains how retries work, when an endpoint is disabled automatically and how to ensure idempotency.

Delivery diagram

POST/api/v1/webhooks/{id}/testTrigger a test delivery to verify an endpoint after fixing it.Full contract in the API Reference

Retry schedule

If your endpoint does not return a 2xx response within 10 seconds, the webhook is retried according to this schedule:

AttemptDelayTime since first attempt
1immediately0
210 seconds10s
31 minute~1 min
45 minutes~6 min
530 minutes~36 min

After five failed attempts, the delivery is marked as failed and failure_count is incremented.

What counts as success?

  • 2xx (200, 201, 202, 204) - success; retries stop
  • Other codes (3xx, 4xx, 5xx) - failure; retry according to the schedule
  • Timeout over 10 seconds - failure; retry
  • Connection refused / DNS error - failure; retry

Automatic disabling after 50 failures

warning

After 50 consecutive failed deliveries, the endpoint is disabled automatically and disabled_at is set to the current timestamp. The webhook endpoint is no longer called.

To reactivate an endpoint after it has been disabled:

  1. Determine why deliveries failed by checking server logs and monitoring
  2. Fix the issue, for example by restoring the endpoint or increasing capacity
  3. Send PATCH /webhooks/{id} with {"is_active": true}; this also resets failure_count
  4. Optionally run a test with POST /webhooks/{id}/test

Monitoring fields

FieldDescription
failure_countConsecutive failed delivery count, reset after a successful delivery
last_triggered_atMost recent delivery attempt
last_success_atMost recent successful delivery
last_failure_atMost recent failed delivery
disabled_atAutomatic disabling date; null while active

Idempotency

warning

Your endpoint must be idempotent. Because of retries, network behavior or timeouts, it may receive the same event more than once. Processing the same event multiple times must not cause errors or duplicate operations.

Implementing idempotency

The simplest approach is to deduplicate by X-Webhook-Id:

<?php
$webhookId = $_SERVER['HTTP_X_WEBHOOK_ID'] ?? '';

// Check whether the event has already been processed
if (alreadyProcessed($webhookId)) {
http_response_code(200);
exit('Already processed');
}

// Process the webhook...
processEvent($event);

// Mark as processed
markAsProcessed($webhookId);

http_response_code(200);
echo 'OK';

Alternative - deduplicate by session and status

<?php
$sessionId = $event['data']['verification_session_id'];
$status = $event['data']['status'];

$existing = getOrder($sessionId);

if ($existing && $existing['status'] === 'verified') {
// Already verified - do nothing
http_response_code(200);
exit('OK');
}

// Update the status
updateOrderStatus($sessionId, $status);
http_response_code(200);

Best practices

  • Respond quickly (under 1s) - perform only essential work synchronously and queue the rest
  • Use a queue such as Redis, RabbitMQ or SQS - accept the webhook, enqueue it, return 200 and process it in a worker
  • Log webhooks - record X-Webhook-Id, the payload and response time for diagnostics
  • Monitor failure_count - alert when a webhook has more than five consecutive failures
  • Test before production - use POST /webhooks/{id}/test to verify the configuration
  • Always verify the signature - see HMAC signature

What if a webhook was not delivered?

If a webhook was not delivered, for example because your endpoint was unavailable for more than 36 minutes, you can always use:

  1. Polling - periodically check the session status with GET /verifications/{id}
  2. Reconciliation - compare the GET /verifications session list with your local database each day
  3. Panel - retrieve the result manually in the administration panel

Webhooks are the fastest method, but they are not the only source of truth.