New France e-invoicing mandate goes live September 2026 — our implementation is ready. See all mandates →
Guides

Webhooks & events

Register an endpoint URL to receive a signed JSON payload the moment something changes — an invoice clearance status, an inbound Peppol delivery, a Spain SII reporting-batch deadline — instead of polling. One webhook subscription covers events from every product on your account.

Guides

Register a webhook

Deliveries retry automatically (up to 10 attempts) until your endpoint returns a 2xx response.

cURL
curl https://api.clearvo.io/v1/webhooks \
  -X POST \
  -H "x-api-key: csk_live_••••••••••••" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-app.com/webhooks/clearvo",
    "events": ["invoice.accepted", "invoice.rejected"],
    "secret": "whsec_your_own_signing_secret"
  }'

Subscribe to "*" to receive every event instead of naming each one.

EventFires when
invoice.acceptedThe authority cleared the invoice.
invoice.rejectedThe authority — or, for France, the buyer — rejected the invoice.
invoice.receivedA new inbound invoice arrived from a supplier (Poland KSeF, France, or Peppol AS4).
invoice.duplicateThe submission matched an existing invoice's idempotency key.
invoice.pendingThe authority is still processing — no terminal outcome yet.
invoice.amended / invoice.cancelledSpain SII: an A1 amendment or Baja was accepted by AEAT.
held_unmapped_decisionNo compliance-mandate rule matched the transaction — held on our side, not a fault on yours.
reporting_batch.*Spain SII reporting-batch reminders — ready for review, deadline approaching or passed, overdue.

Verify the signature

Every delivery is signed with HMAC-SHA256 over {timestamp}.{body}, using the secret you registered. Reject any request whose signature doesn't match before processing the payload.

HTTP
x-taxually-signature: sha256=5f3d...
x-taxually-timestamp: 1758067200
x-taxually-webhook-id: a1b2c3d4-...
x-taxually-delivery-id: d4c3b2a1-...
JavaScript
const crypto = require('crypto');

function isValidSignature(body, headers, secret) {
  const expected = crypto
    .createHmac('sha256', secret)
    .update(`${headers['x-taxually-timestamp']}.${body}`)
    .digest('hex');
  return headers['x-taxually-signature'] === `sha256=${expected}`;
}

Manage your endpoints

MethodPathPurpose
GET/webhooksList registered endpoints.
POST/webhooksRegister a new endpoint.
DELETE/webhooks/{id}Remove an endpoint.
Deliveries retry up to 10 times against a failing endpoint. If every retry is exhausted, we email your entity's users so you don't need to build your own dead-letter monitoring.