Webhooks
Webhooks push events from EncryptInvoice to your systems, so you don't have to poll. You manage subscriptions entirely via the API — see the WebhookSubscription section of the reference.
Subscribing
curl -X POST "https://app.encryptinvoice.com/api/v1/webhooks" \
-H "Authorization: Bearer {{access_token}}" \
-H "X-Organization-Id: {{organization_id}}" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/hooks/encryptinvoice",
"events": ["invoice.paid", "invoice.overdue"],
"secret": "your-signing-secret"
}'
If you omit secret, one is generated for you and returned once — store it; it signs every delivery.
Available events
GET /api/v1/webhooks/events returns the live catalog. Currently:
| Event | Fires when |
|---|---|
invoice.created / invoice.updated |
An invoice is created / changed |
invoice.sent |
An invoice is sent to the customer |
invoice.paid |
An invoice is fully paid |
invoice.overdue |
An invoice passes its due date unpaid |
quote.created |
A quote is created |
quote.accepted / quote.rejected |
A customer accepts / rejects a quote |
expense.created |
An expense is recorded |
customer.created |
A customer is created |
einvoice.sent / einvoice.delivered / einvoice.failed |
E-invoicing network lifecycle |
Verifying deliveries
Each delivery is a POST to your URL with the signature header:
X-Webhook-Signature: <hex HMAC-SHA256 of the raw request body, keyed with your secret>
Verify before trusting the payload:
$expected = hash_hmac('sha256', $rawBody, $secret);
abort_unless(hash_equals($expected, $request->header('X-Webhook-Signature')), 401);
Respond with a 2xx quickly (do the real work asynchronously). Non-2xx responses are recorded in the delivery log.
Testing and monitoring
| Endpoint | Purpose |
|---|---|
POST /api/v1/webhooks/{id}/test |
Sends a signed test payload to your URL |
GET /api/v1/webhooks/{id}/logs |
Recent deliveries with status codes and responses |