Webhooks

Configure webhook endpoints for real-time event notifications including payload format, event types, security signatures, and retry policy.

Last updated: 2025-02-18

Webhooks

Certexi can send real-time HTTP notifications to your systems when events occur. Webhooks enable integration with external ERP systems, notification services, and custom automation.

Configuration

Register webhook endpoints through the admin dashboard or API:

POST /api/webhooks
Content-Type: application/json

{
  "url": "https://your-system.com/webhooks/certexi",
  "events": ["event.created", "transport_unit.stage_changed", "incident.created"],
  "secret": "your-webhook-secret",
  "active": true
}
FieldTypeDescription
urlstringHTTPS endpoint to receive webhook payloads
eventsstring[]Event types to subscribe to
secretstringShared secret for HMAC signature verification
activebooleanEnable or disable the webhook
⚠️

HTTPS Required

Webhook URLs must use HTTPS. HTTP endpoints are rejected to prevent credential exposure in transit.

Event Types

Workflow Events

EventTrigger
event.createdAny event created in the system
transport_unit.createdNew transport unit registered
transport_unit.stage_changedUnit progressed to next workflow stage
transport_unit.completedUnit completed all workflow stages

WHMS Events

EventTrigger
whms.placementAsset placed in a slot
whms.removalAsset removed from a slot
whms.verificationPlacement verified by supervisor
whms.disputePlacement disputed by supervisor

Compliance Events

EventTrigger
incident.createdNew incident reported
incident.resolvedIncident marked as resolved
audit.report_generatedCompliance report generated

IoT Events

EventTrigger
motion.detectedMotion detected on a camera
scale.readingNew scale reading recorded

Payload Format

All webhook payloads follow a consistent structure:

{
  "id": "evt_abc123",
  "type": "transport_unit.stage_changed",
  "timestamp": "2025-01-15T14:30:00Z",
  "data": {
    "transportUnitId": "TU-2024-00042",
    "fromStage": "bascula",
    "toStage": "supervisor",
    "operator": "op-123",
    "evidence": {
      "photos": 2,
      "scaleReading": 24500
    }
  },
  "metadata": {
    "warehouseId": 1,
    "siteId": "site-main",
    "version": "2.0.0"
  }
}

Security

HMAC Signature Verification

Every webhook request includes a signature header for payload verification:

X-Certexi-Signature: sha256=<hmac_hex>

Verify the signature in your endpoint:

import crypto from 'crypto';

function verifyWebhook(
  payload: string,
  signature: string,
  secret: string
): boolean {
  const expected =
    'sha256=' +
    crypto.createHmac('sha256', secret).update(payload, 'utf8').digest('hex');
  return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
}
🚨

Always Verify Signatures

Never process webhook payloads without verifying the HMAC signature. This prevents replay attacks and payload tampering.

Additional Headers

HeaderDescription
X-Certexi-EventEvent type (e.g., transport_unit.stage_changed)
X-Certexi-DeliveryUnique delivery ID for deduplication
X-Certexi-TimestampISO 8601 timestamp of the event
X-Certexi-SignatureHMAC-SHA256 signature

Retry Policy

Failed deliveries are retried with exponential backoff:

AttemptDelay
1Immediate
21 minute
35 minutes
430 minutes
52 hours
612 hours

A delivery is considered failed if:

  • The endpoint returns a non-2xx status code
  • The connection times out (30-second timeout)
  • The endpoint is unreachable

After 6 failed attempts, the webhook is marked as failing and an alert is sent to the admin dashboard. Webhooks are automatically disabled after 100 consecutive failures.

Webhook Payload Card

<Card className="w-full">
  <CardHeader className="pb-2">
    <div className="flex items-center justify-between">
      <CardTitle className="text-sm font-mono">transport_unit.stage_changed</CardTitle>
      <Badge className="bg-green-500 text-white text-[10px]">200 OK</Badge>
    </div>
    <CardDescription>Delivered 2.3s ago — Attempt 1/6</CardDescription>
  </CardHeader>
  <CardContent className="space-y-2">
    <div className="bg-muted/50 rounded p-2 font-mono text-[11px] leading-relaxed">
      <div>{"{"}</div>
      <div className="pl-3">"type": "transport_unit.stage_changed",</div>
      <div className="pl-3">"data": {"{"}</div>
      <div className="pl-6">"transportUnitId": "TU-2025-00042",</div>
      <div className="pl-6">"fromStage": "bascula",</div>
      <div className="pl-6">"toStage": "supervisor"</div>
      <div className="pl-3">{"}"}</div>
      <div>{"}"}</div>
    </div>
    <div className="flex items-center gap-2 text-[10px] text-muted-foreground">
      <span>X-Certexi-Signature: sha256:a4f2e8...</span>
    </div>
  </CardContent>
</Card>

Testing

Use the webhook test endpoint to send a sample payload:

POST /api/webhooks/:id/test

This sends a webhook.test event to the registered URL without affecting production data.

Webhooks | Certexi Docs