Webhooks
Recevez, vérifiez et dédupliquez les événements de l’API YAOKA.
Configuration
Dans Portail développeur → Webhooks, ajoutez une URL HTTPS publique et sélectionnez les événements utiles. Copiez le secret whsec_... lors de son unique affichage et stockez-le dans un gestionnaire de secrets.
En-têtes envoyés
X-Yaoka-Signature: t=1785801600,v1=4e8f...
X-Yaoka-Key-Version: 1
X-Yaoka-Event-Id: evt_...
User-Agent: YAOKA-Webhooks/1.0Le timestamp et la signature sont regroupés dans X-Yaoka-Signature. Le type d’événement se trouve dans le champ event du corps JSON.
Corps d’un événement
{
"apiVersion": "v1",
"schemaVersion": 1,
"sourceProduct": "core",
"event": "invoice.finalized",
"eventId": "evt_...",
"organizationId": "org_...",
"timestamp": 1785801600,
"occurredAt": "2026-08-04T00:00:00.000Z",
"subject": { "type": "invoice", "id": "inv_..." },
"data": { "invoiceId": "inv_...", "number": "F-2026-0001" }
}La livraison est « au moins une fois ». Dédupliquez vos traitements avec eventId ou X-Yaoka-Event-Id avant de modifier vos données.
Vérifier la signature
Calculez le HMAC SHA-256 de timestamp + "." + rawBody avec le secret, puis comparez les empreintes en temps constant. Utilisez impérativement le corps HTTP brut avant tout parsing JSON.
import { createHmac, timingSafeEqual } from "node:crypto";
export function verifyYaokaWebhook(
rawBody: string,
header: string,
secret: string,
) {
const values = Object.fromEntries(
header.split(",").map((part) => part.split("=", 2)),
);
const timestamp = values.t;
const received = values.v1;
if (!timestamp || !received) return false;
const age = Math.abs(Date.now() / 1000 - Number(timestamp));
if (!Number.isFinite(age) || age > 300) return false;
const expected = createHmac("sha256", secret)
.update(`${timestamp}.${rawBody}`)
.digest("hex");
return (
expected.length === received.length &&
timingSafeEqual(Buffer.from(expected), Buffer.from(received))
);
}Répondez en 2xx dès que l’événement est validé et placé dans votre file de traitement. Les erreurs sont retentées jusqu’à 6 fois, après environ 1 min, 5 min, 30 min, 2 h, 6 h puis 12 h.
Événements publics
| Ressource | Événements |
|---|---|
| Clients | customer.created, customer.updated |
| Devis | quote.created, quote.updated, quote.finalized, quote.converted |
| Factures | invoice.created, invoice.updated, invoice.finalized, invoice.paid, invoice.overdue |
| Avoirs | credit_note.created |
Checklist du handler
- Lire le corps brut.
- Vérifier
X-Yaoka-Signatureet refuser un timestamp âgé de plus de 5 minutes. - Vérifier que
eventIdn’a pas déjà été traité. - Placer le travail métier dans une file.
- Répondre rapidement en
2xx.