Webhooks
Public event and role details are on the Webhooks page. Full-access OAuth apps (including partners) can subscribe to invoice events for invoices they own or entities they can read, and to client.onboarded for their own partner referrals. A reseller account's app can receive only client.onboarded through /oauth/reseller/webhooks; an E-Invoice account with reseller access keeps the full API too. invoice.delivered is accepted by the event catalogue but is not currently emitted. Invoice deliveries are attempted once; client.onboarded is retried up to 8 times.
Webhook events and who receives them
This reference is public; you do not need to sign in to read it. Subscribe to one or more event names when creating a webhook. The * subscription means all event types available to that API route, including event types added in the future.
| Event | When it is sent | Which app can receive it |
|---|---|---|
| invoice.sent | A sent OAuth invoice reaches the sent-to-Peppol status. | The OAuth app that owns the sent invoice. |
| invoice.delivered | Reserved in the event catalogue for delivery to the recipient. | Not currently emitted by the invoice webhook sender. |
| invoice.failed | An invoice status is classified as a failure, for a sent or received invoice. | Sent: the app that owns the invoice. Received: apps that can read the receiving entity. |
| invoice.received | A received invoice reaches the received-by-Tax-Star status. | Apps that can read the receiving entity. |
| invoice.status_changed | A status update has no more specific event name (for example, an intermediate status). | A subscription to this event also receives every invoice status event; the payload keeps its specific event name when one applies. |
| client.onboarded | A client you pre-registered by TIN is registered, or is linked immediately because its company already exists. | The partner or reseller app that made the successful pre-registration. |
OAuth apps, partners and resellers
A partner is an audience using a regular full-access OAuth app, not a separate account type. Its invoice-event access follows the same rules as any other full-access OAuth app. If it pre-registers clients, it can also receive their client.onboarded events through /oauth/webhooks or this page's Webhooks panel. The event catalogue for this route is available at GET /oauth/webhooks/event-types.
A reseller account's app is limited to the reseller API and GET /oauth/me. It receives only client.onboarded for its own successfully pre-registered clients, and manages that subscription through /oauth/reseller/webhooks; it cannot subscribe to invoice events or use the Webhooks panel here. Its event list is GET /oauth/reseller/webhooks/event-types. An E-Invoice account that has been granted reseller access keeps its full OAuth API as well: its regular OAuth app can receive invoice events, and it can use the reseller webhook route for reseller-client onboarding events.
For received invoices, an app is eligible when the person who owns that app can read the receiving company: an admin, editor, approver or viewer. For sent invoices, status events go to the app that owns the sent OAuth invoice. A partner's linked client becomes accessible to the partner under the rules described in Partner overview; a reseller is not added as a company member and receives no invoice events for that client.
Payloads and delivery
Invoice payloads have the envelope event, created_at and data. Sent data includes direction, invoice_id, invoice_number,entity_id and status. Received data includes direction: "received", invoice_number, receiver_registry_code, entity_id and status. The status contains its current code, message and timestamp; internal XML fields are omitted.
Invoice events are attempted once with a 10-second timeout. Failed or timed-out invoice deliveries are not retried and cannot be replayed; use the sent or received invoice list with date_from to catch up. Client onboarding events are delivered by a scheduler (sometimes about a minute later), retried with backoff up to 8 attempts, and then abandoned. They include the client's id, TIN, company name, status and timestamps, never its email; poll your pre-registered-client list to catch up.
Manage webhooks
Add webhook endpoints to your application, then send a test event to verify the connection before going live. Tax Star POSTs signed payloads for the events you select: sent invoices owned by your app and received invoices for companies your app can read. See the public event and access reference above; partner and reseller client-onboarding events have their own route rules.
How delivery works
For each event matching one of your subscriptions, Tax Star sends an HTTP POST to your url with a JSON body and an X-Taxstar-Signature header. Return a 2xx status to acknowledge. Always verify the signature before trusting a payload. The X-Taxstar-Event header also names the event.
{
"event": "invoice.sent",
"created_at": "2026-06-21T10:00:00Z",
"data": {
"direction": "sent",
"invoice_id": "6a3e3e160c9fbfd76f261711",
"invoice_number": "INV-1001",
"entity_id": "6a3e388e7a5b528a20bc5149",
"status": {
"code": "SENT_TO_PEPPOL",
"message": "Invoice sent to Billberry successfully",
"created_at": "2026-06-21T10:00:00Z"
}
}
}// Node.js (Express) — verify an incoming Taxstar webhook
import crypto from "crypto";
function verify(req, signingSecret) {
// header: "X-Taxstar-Signature: t=<unix_ts>,v1=<hex hmac-sha256>"
const header = req.headers["x-taxstar-signature"] || "";
const parts = Object.fromEntries(
header.split(",").map((kv) => kv.split("="))
);
const t = parts.t;
const signed = `${t}.${req.rawBody}`; // raw, unparsed JSON body
const expected = crypto
.createHmac("sha256", signingSecret)
.update(signed)
.digest("hex");
// constant-time compare; optionally reject if |now - t| is too large
return crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(parts.v1 || "")
);
}Received-invoice events carry invoice_number and receiver_registry_code in data instead of invoice_id, with direction: "received".