Skip to main content
ArrowLeftDeveloper Portal

Webhooks

Receive real-time HTTP notifications when events happen on Cantarell OS.

Settings
How webhooks work

  1. Register a webhook URL and select event types (or use * for all)
  2. When an event occurs, we POST a JSON payload to your URL
  3. We include an HMAC-SHA256 signature in the X-Cantarell-Signature-256 header
  4. Respond with 2xx within 10 seconds to acknowledge receipt
  5. On failure, we retry with exponential backoff: 1m, 5m, 30m, 2h, 24h
  6. After 5 consecutive failures, the subscription is paused (circuit breaker)

FileJson
Payload structure

{
  "event": "order.created",
  "event_id": "evt_a1b2c3d4",
  "organization_id": "org_xyz789",
  "data": {
    "id": "ORD-2024-001",
    "product": "Magna",
    "volume_liters": 10000,
    "total_mxn": 225000.00,
    "status": "created"
  },
  "created_at": "2026-03-07T10:00:00Z"
}

Request headers

HeaderDescription
X-Cantarell-Signature-256HMAC-SHA256 hex digest
X-Cantarell-TimestampUnix timestamp (for replay prevention)
X-Cantarell-Delivery-IdUnique delivery ID (for idempotency)
X-Cantarell-EventEvent type (e.g., order.created)

Signature verification

Always verify the signature before processing a webhook to prevent spoofing.

import hmac, hashlib, time

def verify_webhook(secret, payload_body, signature, timestamp, tolerance=300):
    """Verify a Cantarell OS webhook signature."""
    now = int(time.time())
    if abs(now - int(timestamp)) > tolerance:
        return False  # Replay attack protection

    signed_content = f"{timestamp}.{payload_body}"
    expected = hmac.new(
        secret.encode(), signed_content.encode(), hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(expected, signature)

# In your webhook handler:
# signature = request.headers["X-Cantarell-Signature-256"]
# timestamp = request.headers["X-Cantarell-Timestamp"]
# is_valid = verify_webhook(secret, request.body, signature, timestamp)

Event catalog

Orders

order.createdA new order was placed on the marketplace.
order.confirmedThe seller confirmed the order.
order.shippedThe order has been dispatched for delivery.
order.deliveredThe order was delivered to the buyer.
order.cancelledThe order was cancelled.
order.refundedA refund was issued for the order.

Payments

payment.initiatedA payment was initiated (SPEI or ACH).
payment.receivedPayment was successfully received.
payment.sentAn outbound payment was sent.
payment.failedA payment attempt failed.
payment.settledThe payment was fully settled.

Credit

credit.score_updatedThe organization credit score was recalculated.
credit.facility_approvedA credit facility was approved.
credit.facility_frozenA credit facility was frozen due to risk.
credit.risk_eventA risk event was detected.

Compliance

compliance.permit_expiringA CRE/FMCSA permit is expiring within 30 days.
compliance.permit_expiredA permit has expired.
compliance.alertA compliance alert was triggered.
compliance.report_filedA regulatory report was filed.

Fleet

fleet.vehicle_addedA vehicle was added to the fleet.
fleet.trip_startedA vehicle started a trip.
fleet.trip_completedA vehicle completed a trip.
fleet.maintenance_dueA vehicle has maintenance due.

SCF

scf.invoice_factoredAn invoice was factored.
scf.repayment_receivedA factoring repayment was received.
scf.facility_updatedAn SCF facility was updated.

FX

fx.forward_createdAn FX forward contract was created.
fx.forward_settledAn FX forward was settled.
fx.rate_alertAn FX rate threshold was triggered.

Account

account.createdA new account was created.
account.balance_updatedA virtual account balance changed.
account.kyc_approvedKYC verification was approved.

Repeat
Retry policy

AttemptDelayTotal elapsed
1st retry1 minute~1 min
2nd retry5 minutes~6 min
3rd retry30 minutes~36 min
4th retry2 hours~2.5 hours
5th retry (final)24 hours~26.5 hours

Circuit Breaker Enabled
After 5 consecutive failures, the subscription is automatically paused to prevent cascading failures. You can manually reactivate it from the developer dashboard once your endpoint is healthy.