Skip to main content

Webhooks

Webhooks allow you to receive real-time HTTP notifications when events occur in your Covered account.

How webhooks work

  1. You register a webhook endpoint URL in your dashboard or via API
  2. When an event occurs (e.g., a payment is completed), Covered sends an HTTP POST request to your endpoint
  3. Your server processes the event and returns a 2xx response

Event types

Payables (Accounts Payable)

EventDescription
payable.createdA new payable was created or imported
payable.approvedA payable was approved for payment
payable.processingPayment is being processed
payable.paidVendor payment completed successfully
payable.failedVendor payment failed

Receivables (Accounts Receivable)

EventDescription
receivable.createdA new receivable was created
receivable.sentInvoice was sent to customer
receivable.viewedCustomer viewed the invoice
receivable.paidCustomer payment received
receivable.overdueInvoice is past due date

Treasury

EventDescription
treasury.depositFunds deposited to treasury
treasury.withdrawalFunds withdrawn from treasury

Webhook payload

All webhook payloads follow this structure:
{
  "id": "msg_2xYz3...",
  "type": "payable.paid",
  "timestamp": "2024-01-15T10:30:00Z",
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "invoice_number": "INV-001",
    "vendor_name": "Acme Software",
    "amount": 5000.00,
    "payment_method": "ach",
    "transaction_id": "txn_abc123",
    "paid_at": "2024-01-15T10:30:00Z"
  }
}

Verifying signatures

Webhook requests include a signature in the svix-signature header. Always verify this signature to ensure the webhook is from Covered.
import { Webhook } from 'svix';

const webhook = new Webhook(process.env.WEBHOOK_SECRET);

app.post('/webhooks/covered', (req, res) => {
  const headers = {
    'svix-id': req.headers['svix-id'],
    'svix-timestamp': req.headers['svix-timestamp'],
    'svix-signature': req.headers['svix-signature'],
  };

  try {
    const event = webhook.verify(JSON.stringify(req.body), headers);
    // Process the event
    console.log('Received event:', event.type);
    res.status(200).send('OK');
  } catch (err) {
    console.error('Webhook verification failed:', err);
    res.status(400).send('Invalid signature');
  }
});

Retry policy

If your endpoint returns a non-2xx status code or times out, Covered will retry the webhook:
  • Immediate retry: After 5 seconds
  • Second retry: After 5 minutes
  • Third retry: After 30 minutes
  • Fourth retry: After 2 hours
  • Fifth retry: After 5 hours
  • Final retry: After 10 hours
After all retries are exhausted, the webhook is marked as failed.

Best practices

Process webhooks asynchronously. Return a 200 response immediately and handle the event in a background job.
Use the webhook id to deduplicate events. The same event may be delivered multiple times.
Always use HTTPS endpoints to ensure webhook data is encrypted in transit.
Check the Svix dashboard (accessible from Settings → Webhooks → Open Dashboard) to monitor delivery status.

Testing webhooks

Use the test endpoint to send a sample webhook to your endpoint:
curl -X POST https://api.allcovered.xyz/v1/webhooks/{id}/test \
  -H "Authorization: Bearer cov_xxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{"event_type": "payable.paid"}'