API reference

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.

EventWhen it is sentWhich app can receive it
invoice.sentA sent OAuth invoice reaches the sent-to-Peppol status.The OAuth app that owns the sent invoice.
invoice.deliveredReserved in the event catalogue for delivery to the recipient.Not currently emitted by the invoice webhook sender.
invoice.failedAn 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.receivedA received invoice reaches the received-by-Tax-Star status.Apps that can read the receiving entity.
invoice.status_changedA 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.onboardedA 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.

Sign in with your Tax Star developer account to manage your webhooks.

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.

Example event payload
{
  "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"
    }
  }
}
Verifying the signature
// 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".