Skip to content
MCPInvoice from your AI
Factuarea

Webhooks

Every change reaches your system. Signed and deduplicated.

Factuarea notifies your server when an invoice changes, gets paid or fails. If you do not answer, it retries automatically.

  • HMAC-SHA256 signature
  • Eight attempts over more than 4 days
  • Delivery replay

Compatible integrations and formats

  • Stripe
  • WhatsAppWhatsApp
  • Facturae
invoice.paid
FactuareaFactuarea

Your server

POST /webhook

200 OK

The event leaves signed. If delivery repeats, it keeps the same identifier so you process it only once.

  • Signed

    HMAC-SHA256

  • Deduplication

    Stable Event-Id

  • 8 attempts

    backoff + jitter

Verifying the signature

HMAC-SHA256 verification in four steps

The Factuarea-Signature header carries the moment of the delivery and the HMAC-SHA256 of t.body computed with your secret. Verifying it is easy; verifying it badly is even easier.

  1. 1

    Sign over the raw body

    The HMAC is computed over the bytes that arrived, not over the JSON your framework already parsed and serialised again.

  2. 2

    Compare in constant time

    timingSafeEqual, hash_equals or whatever your language brings to compare without leaking where it fails.

  3. 3

    Look at the clock

    The header carries t with the UNIX moment of the delivery. Reject it if more than 300 seconds have gone by.

  4. 4

    Accept either v1

    For the 24 hours after a rotation the header carries two signatures. It is enough for one of them to match.

Node · the whole verifier

import { createHmac, timingSafeEqual } from "node:crypto"; // `cuerpo` son los BYTES que llegaron, sin parsear ni volver a serializar.export function firmaValida(cuerpo, cabecera, secreto) {  const partes = cabecera.split(",").map((p) => p.split("="));  const t = Number(partes.find(([clave]) => clave === "t")?.[1]);  const firmas = partes.filter(([clave]) => clave === "v1").map(([, v]) => v);   // Ventana de 5 minutos: una entrega capturada no vale para mañana.  if (!t || Math.abs(Date.now() / 1000 - t) > 300) return false;   const esperada = createHmac("sha256", secreto)    .update(`${t}.${cuerpo}`)    .digest("hex");   // Durante una rotación llegan dos v1. Basta con que cuadre uno.  return firmas.some(    (firma) =>      firma.length === esperada.length &&      timingSafeEqual(Buffer.from(firma), Buffer.from(esperada))  );}

When your server does not answer

If your server goes down, we call again

Every event arrives signed and keeps the same identifier. You can retry it without processing it twice.

  • Any 2xx responseDelivery closed. We keep the status code and how long you took, and that is the end of it.
  • 408, 425 and 429These are the only transient 4xx responses and they are retried. Other 4xx responses are marked as permanent failures so you can fix the request and replay it later.
  • 5xx, timeout or silenceInto the queue. Eight attempts in total, with growing waits: the first retry after a minute, the last one three days later.
Factuarea
Your server200 OK

Signed

HMAC-SHA256

Deduplication

Stable Event-Id

8 attempts

backoff + jitter

invoice.emittedinvoice.cancelledverifactu.status.updated

Rotating the secret

Secret rotation with a 24-hour transition

The plaintext secret is shown once only, when you create the endpoint and when you rotate it. It is then stored encrypted for signing deliveries and also as a hash for verification. Rotation causes no interruption if you follow the order.

BeforeYou rotate · 24 h graceAfter

Previous secret

New secret

During the window every delivery goes out signed twice: the header carries t, the v1 of the new secret and the v1 of the previous one. Your verifier takes the signature as good if either of the two matches.

The order that loses no event

  1. 1

    Make your server accept both secrets at once.

  2. 2

    Rotate, and store the new one: it is shown only once.

  3. 3

    Deploy the new secret to your server.

  4. 4

    Before the 24 hours are up, drop the old one.

You cannot rotate twice within five minutes

That guard rail is deliberate. Two rotations in a row would leave out the secret your server has just learnt, and that is when deliveries really do fall.

Rotation and dual signing, in the guide

Published surface

An integration that fits your stack

The OpenAPI contract, SDKs and MCP server share the same API. These figures are checked against the published surface so you can assess scope and maintenance before integrating.

API operations
413
resources
37
MCP tools
391
documentation pages
797

Compatible technologies and clients

  • Official Stripe logoStripe
  • Official TypeScript logoTypeScript
  • Official PHP logoPHP
  • Official OpenAPI logoOpenAPI

Logos identify compatible technologies or clients; they do not imply a commercial relationship or endorsement.

Before going live

Common webhook questions

Verify the Factuarea-Signature header with HMAC-SHA256, the unmodified body and a five-minute tolerance. The official SDKs include the verifier to avoid serialisation differences.

Grab a test key and send a ping

The whole circuit (create the endpoint, sign, fail, retry, replay) can be tried in sandbox without touching anything real. The test key takes a minute to get from the dashboard.