Concept
A webhook is an HTTPS endpoint you control that Prevayl calls when something happens. Faster than polling, more reliable than email parsing.
Example flow: a customer pays an invoice. Prevayl POSTs an invoice.paid event to your webhook URL. Your system updates the customer's ledger and sends a thank-you email — without ever calling Prevayl's API.
Event types
| Event | Fires when |
|---|---|
| order.created | New order created via API or dashboard |
| order.dispatched | Carrier accepted the load |
| order.in_transit | Carrier completed pickup, vehicle moving |
| order.delivered | BOL signed at delivery |
| order.cancelled | Order cancelled before pickup |
| order.exception | Exception flagged (delay, damage, dispute) |
| carrier.onboarded | Carrier completed initial application |
| carrier.vetted | SAFER + insurance verification passed |
| carrier.suspended | Carrier suspended (insurance lapsed, etc.) |
| invoice.created | Invoice generated (DRAFT or SENT) |
| invoice.sent | Invoice emailed/posted to customer |
| invoice.paid | Customer payment received and applied |
| invoice.voided | Invoice voided after issuance |
| payment.received | Any inbound payment recorded |
| payment.failed | Payment attempt failed |
| carrier_payment.sent | Bill payment dispatched to carrier |
| compliance.alert | BOC-3 expiry, bond lapse, COI lapse, etc. |
| audit.privileged_action | Privileged action recorded in audit log |
Payload shape
POST https://your-app.example.com/webhooks/prevayl
Content-Type: application/json
Prevayl-Signature: t=1714560000,v1=ed4c8...
Prevayl-Event-Id: evt_8kJsD...
{
"id": "evt_8kJsD...",
"type": "invoice.paid",
"created": 1714560000,
"data": {
"id": "inv_4kJsD...",
"amount": 4840,
"currency": "USD",
"customer_id": "cus_4kJsD...",
"paid_at": 1714559800,
"payment_method": "ach"
}
}Verifying signatures
Every webhook request includes a Prevayl-Signature header. Verify it on your end before acting on the payload.
// Node.js example
const crypto = require('crypto');
function verifyPrevayl(req, secret) {
const sig = req.headers['prevayl-signature'];
const [tPart, v1Part] = sig.split(',');
const timestamp = tPart.split('=')[1];
const signature = v1Part.split('=')[1];
const payload = timestamp + '.' + req.rawBody;
const expected = crypto.createHmac('sha256', secret)
.update(payload).digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature, 'hex'),
Buffer.from(expected, 'hex')
);
}timestampto your server's clock). This prevents replay attacks even if the signing secret leaks temporarily.Retries
If your endpoint returns anything other than 2xx, Prevayl retries with exponential backoff:
- Attempt 1: immediately
- Attempt 2: 30 seconds later
- Attempt 3: 5 minutes later
- Attempt 4: 30 minutes later
- Attempt 5: 6 hours later
- Attempt 6: 24 hours later
After 6 failed attempts the event is marked permanently_failed and you're notified via the webhook delivery log. You can replay any event manually from the dashboard.
Idempotency
Each event has a unique Prevayl-Event-Id header. Your webhook handler should record received event IDs and ignore duplicates. Network retries can deliver the same event multiple times — your handler must be idempotent.
Configuring endpoints
From the dashboard: Settings → Developers → Webhooks → + Add Endpoint. Specify:
- URL (must be HTTPS)
- Events to subscribe to (or all)
- API version (pinned at endpoint creation)
- Description (for your team's reference)
Or programmatically via POST /v1/webhook_endpoints.
Related
- REST API — for read operations and writes
- Zapier Integration — no-code alternative