Skip to main content

What are Webhooks?

Webhooks allow you to receive real-time HTTP notifications when trading events occur on your account, eliminating the need to poll the API for order status updates.
Webhooks are the recommended way to track order execution and trade activity. They provide real-time updates and reduce API load.

Supported Events

EventDescriptionWhen Triggered
order.createdOrder submittedNew order accepted by the matching engine
order.filledOrder completely filledAll quantity executed
order.partially_filledOrder partially filledSome quantity executed, order still open
order.cancelledOrder cancelledUser cancelled or system cancelled
order.rejectedOrder rejectedValidation failed or insufficient balance
trade.executedTrade executedA trade matched involving your order

Webhook Configuration

Configure webhook endpoints in your Daya Pro Dashboard:
  1. Navigate to API Settings > Webhooks
  2. Add webhook URL (must be HTTPS)
  3. Generate webhook secret
  4. Select events to subscribe to
Webhook URLs must use HTTPS in production. HTTP is only allowed for local development testing.

HTTP Headers

All webhook requests include the following headers:
HeaderDescriptionExample
Content-TypeAlways application/jsonapplication/json
X-Webhook-SignatureHMAC-SHA256 signature with sha256= prefixsha256=a8f5f167f44f...
X-Webhook-EventEvent type that triggered this webhookorder.filled
X-Webhook-IDUnique event identifier (UUID)550e8400-e29b-41d4-a716-446655440000
X-Webhook-TimestampWhen the event occurred (RFC3339)2026-01-14T15:08:15Z
User-AgentIdentifies Daya as the senderDaya-Webhook/1.0

Webhook Payload

All webhook events follow this structure:
{
  "event_id": "550e8400-e29b-41d4-a716-446655440000",
  "type": "order.filled",
  "timestamp": "2026-01-14T15:08:15Z",
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "symbol": "USD-NGN",
    "side": "buy",
    "type": "limit",
    "status": "filled",
    "price": "1545.00",
    "quantity": "100.00",
    "filled_quantity": "100.00",
    "executed_price": "1545.00",
    "base_asset": "USD",
    "quote_asset": "NGN",
    "created_at": "2026-01-14T15:06:30Z",
    "updated_at": "2026-01-14T15:08:15Z"
  }
}

Common Fields

event_id
string
Unique identifier for this event (UUID format)Use for: Idempotency (deduplicate multiple deliveries)
type
string
Event typeValues: order.created, order.filled, order.partially_filled, order.cancelled, order.rejected, trade.executed
timestamp
string
When event occurred (RFC3339 timestamp)
data
object
Event-specific data (varies by event type)

Event-Specific Payloads

Sent when: New order accepted by matching engine
{
  "event_id": "550e8400-e29b-41d4-a716-446655440000",
  "type": "order.created",
  "timestamp": "2026-01-14T15:06:30Z",
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "symbol": "USD-NGN",
    "side": "buy",
    "type": "limit",
    "status": "open",
    "price": "1545.00",
    "quantity": "100.00",
    "filled_quantity": "0.00",
    "base_asset": "USD",
    "quote_asset": "NGN",
    "created_at": "2026-01-14T15:06:30Z",
    "updated_at": "2026-01-14T15:06:30Z"
  }
}
Next steps: Monitor for order.filled, order.partially_filled, or order.cancelled

Delivery Guarantees

Webhooks may be delivered multiple times. Your endpoint must handle duplicate deliveries using event_id for idempotency.
Events may arrive out of order. Use created_at timestamps to order events client-side.
If your endpoint returns non-2xx status or times out, Daya retries with exponential backoff:
AttemptDelay After Previous
110 seconds
230 seconds
31 minute
45 minutes
515 minutes
630 minutes
71 hour
82 hours
94 hours
108 hours
After 10 failed attempts, delivery is marked as failed and the webhook may be automatically disabled.
Your endpoint must respond within 30 seconds. Longer responses will timeout and trigger retries.
Webhooks are automatically disabled after 10 consecutive delivery failures. You can re-enable them via the API or dashboard.

Webhook Verification

All webhooks include an HMAC-SHA256 signature in the X-Webhook-Signature header with a sha256= prefix. Always verify signatures to prevent spoofing.
X-Webhook-Signature: sha256=a8f5f167f44f4964e6c998dee827110c447be52d40d67b6a60b78c1e3e01b7e8
See Webhook Verification for implementation details.

Implementing a Webhook Endpoint

Required Response

Your endpoint must:
  1. Verify signature (see Verification)
  2. Return 2xx status to acknowledge receipt
  3. Process quickly (< 10 seconds) or queue for async processing

Example Implementation

const express = require('express');
const crypto = require('crypto');

const app = express();

app.post('/webhooks/daya-pro', express.raw({ type: 'application/json' }), (req, res) => {
  const signatureHeader = req.headers['x-webhook-signature'];
  const payload = req.body.toString('utf8');

  // 1. Verify signature (strip "sha256=" prefix)
  const signature = signatureHeader?.replace('sha256=', '');
  if (!verifySignature(payload, signature, process.env.DAYA_PRO_WEBHOOK_SECRET)) {
    return res.status(401).send('Invalid signature');
  }

  // 2. Parse and check idempotency
  const event = JSON.parse(payload);
  if (isProcessed(event.event_id)) {
    return res.status(200).send('Already processed');
  }

  // 3. Handle event
  switch (event.type) {
    case 'order.filled':
      handleOrderFilled(event.data);
      break;
    case 'order.partially_filled':
      handlePartialFill(event.data);
      break;
    case 'trade.executed':
      handleTradeExecuted(event.data);
      break;
    // ... handle other events
  }

  markAsProcessed(event.event_id);
  res.status(200).send('OK');
});

function verifySignature(payload, signature, secret) {
  const expectedSignature = crypto
    .createHmac('sha256', secret)
    .update(payload)
    .digest('hex');
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expectedSignature)
  );
}

Best Practices

1

Verify signatures

Always verify X-Webhook-Signature to prevent spoofing attacks. Remember to strip the sha256= prefix before comparing.
2

Handle idempotency

Use event_id to deduplicate. Store processed event IDs in your database.
CREATE TABLE processed_webhook_events (
  event_id VARCHAR(255) PRIMARY KEY,
  processed_at TIMESTAMP
);
3

Return 200 quickly

Acknowledge receipt immediately (< 1 second). Queue heavy processing asynchronously.
4

Handle out-of-order delivery

Events may arrive out of order. Use timestamp field and order status to reconcile.
5

Reconcile with API

Periodically call List Orders to reconcile state in case webhooks are missed.

Testing Webhooks

Local Testing

For local development, use tools like ngrok:
# Start ngrok
ngrok http 3000

# Configure webhook URL in dashboard
https://abc123.ngrok.xyz/webhooks/daya-pro
Use ngrok’s web interface (http://localhost:4040) to inspect webhook payloads during development.

Troubleshooting

Possible causes:
  • Firewall blocking Daya’s IPs
  • Endpoint returning non-2xx status
  • SSL certificate issues
Fix: Check endpoint logs, ensure HTTPS, verify firewall rules
Expected behavior: At-least-once delivery means duplicates are possibleFix: Implement idempotency using event_id
Cause: Endpoint taking > 30 seconds to respondFix: Return 200 immediately, queue processing asynchronously
Cause: Wrong secret, payload manipulation, or not stripping sha256= prefixFix: Verify you’re using correct webhook secret and stripping the sha256= prefix from the X-Webhook-Signature header before comparing

Next Steps

Webhook Events

Detailed event schemas

Signature Verification

Implement HMAC verification