Webhooks
Reagieren Sie sofort auf Statusänderungen Ihrer Angebote, ohne die API per Polling abfragen zu müssen.
Warum Webhooks?
Statt dass Ihr System (ein ERP, ein Ablauf in Zapier/Make oder Ihr eigenes Backend) Cord alle 5 Minuten fragt, ob der Kunde schon bezahlt hat, benachrichtigen die Webhooks von Cord Ihr System in dem Moment, in dem das Ereignis eintritt, mit einem signierten HTTP-POST an Ihren Server.
Häufige Anwendungsfälle:
- Automatisch eine Softwarelizenz bereitstellen, wenn ein Angebot den Status
paiderreicht. - Eine interne Nachricht in Slack senden, wenn der Kunde ein Angebot zum ersten Mal ansieht (
viewed). - Den Abrechnungsprozess in Ihrem ERP auslösen, wenn der CFDI gestempelt wird.
Einen Endpoint einrichten
- Aktivieren Sie den Entwicklermodus unter Ihr Konto › Präferenzen – dadurch erscheint die Schaltfläche
„Entwickler“ unten rechts, in der gesamten App sichtbar. Öffnen Sie sie per Klick oder mit der Taste
W. Die vollständige Tour finden Sie unter Cord Workbench. - Öffnen Sie den Tab Webhooks des Panels.
- Klicken Sie auf Endpoint hinzufügen – es öffnet sich ein Assistent im Vollbild.
- Wählen Sie die Ereignisse, die Sie empfangen möchten: Sie sind nach Familien gruppiert, mit Suche und einem Kontrollkästchen pro Familie. Alle Ereignisse (oder gar keine Auswahl) sendet Ihnen alle, auch Ereignistypen, die Cord künftig hinzufügt. Siehe den vollständigen Katalog weiter unten.
- Geben Sie Ihre URL ein – sie muss mit
https://beginnen; Cord lehnt bereits beim Anlegen Ziele mithttp://,localhost, privaten/internen IP-Adressen und Hosts.internal/.localab. - Bewahren Sie eine Kopie Ihres Secrets (
whsec_…) auf – es wird nur einmal im Klartext angezeigt. Danach ist es nur noch maskiert sichtbar. Auf derselben Seite können Sie Testereignis senden.
Ihr Team kann im kostenlosen Tarif sowie in Starter und Professional 16 Endpoints konfigurieren, in Scale 32 und in Developer 100. Abonnements, die Integrationen per API erstellen, haben in allen Tarifen ein eigenes Kontingent von 100 pro Organisation. Webhooks sind NICHT an einen kostenpflichtigen Tarif gebunden.
Der Payload
Jede Zustellung ist ein POST mit Content-Type: application/json und diesem Body:
{
"id": "evt_5f2a1c9e8b3d4a7f6e1c0d9b8a7f6e5c",
"event": "quote.paid",
"created_at": "2026-07-27T18:32:04.000Z",
"data": {
"id": "b3f1c2d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
"folio": "COT-0148",
"status": "paid",
"moneda": "MXN",
"total": 45200.00,
"cliente": "Distribuidora El Zarco",
"cliente_id": "9a1c3e5f-7b2d-4f6a-8c0e-1d3b5f7a9c2e",
"link_publico": "https://cordhq.app/q/6f2a9c4e1b7d3f8a0c5e2b9d4f1a6c3e"
}
}
id ist die Identität des Ereignisses, nicht des Angebots – derselbe Wert bei Wiederholungen und bei einem manuellen Replay (siehe Identität des Ereignisses und Idempotenz). data.id ist die interne ID des Angebots.
Signaturen und Sicherheit
Cord signiert jede Zustellung mit zwei Headern. Verwenden Sie constructEvent aus @flouviahq/node (siehe das
Node-SDK), damit Sie die Verifizierung nicht
selbst implementieren müssen. Die Funktion verlangt X-Cord-Signature-V1 mit Zeitstempel, vergleicht in
konstanter Zeit und lehnt eine Zustellung ab, die älter als 5 Minuten ist:
import { constructEvent } from '@flouviahq/node';
const event = await constructEvent(
await req.text(),
req.headers,
process.env.CORD_WEBHOOK_SECRET!,
);
Jede Zustellung trägt diese Header:
| Header | Inhalt | Hinweise |
|---|---|---|
Content-Type |
application/json |
|
User-Agent |
Cord-Webhooks/1.0 |
|
X-Cord-Event |
quote.paid, ping… |
Der Ereignistyp, identisch mit dem Feld event im Body. Praktisch zum Routing, ohne zu parsen. |
X-Cord-Timestamp |
Unix-Sekunden | Dasselbe t wie in X-Cord-Signature-V1: der Moment, in dem dieser Versuch signiert wurde. |
X-Cord-Signature-V1 |
t=<unix>,v1=<hmac_sha256(secret, "<t>.<body>")> |
Empfohlen. Enthält einen Zeitstempel – echter Schutz vor Replay. Kann während einer Secret-Rotation zwei v1= enthalten (siehe unten); akzeptieren Sie, wenn einer davon passt. |
X-Cord-Signature |
sha256=<hmac_sha256(secret, body)> |
Legacy, ohne Zeitstempel. Wird aus Kompatibilitätsgründen weiterhin bei jeder Zustellung gesendet; verwenden Sie nach Möglichkeit V1. |
X-Cord-Event-Id |
evt_… |
Identisch mit dem Feld id im Body. |
X-Cord-Delivery-Id |
UUID | ID dieses Versuchs – ändert sich bei jeder Wiederholung und jedem Replay, anders als X-Cord-Event-Id. |
X-Cord-Attempt |
Zahl | Beginnt bei 1. |
Idempotency-Key |
evt_… |
Wiederholt X-Cord-Event-Id – mehrere Server-Frameworks lesen ihn direkt von dort. |
Signatur von Hand prüfen
Wenn Sie das SDK nicht verwenden, ist dies der vollständige Algorithmus. Er entspricht dem, was constructEvent tut:
- Lesen Sie den rohen Body, genau so, wie er angekommen ist. Geparstes und wieder serialisiertes JSON passt nicht.
- Entnehmen Sie dem Header
X-Cord-Signature-V1den Werttund allev1-Werte (während einer Rotation kommen zwei an). - Lehnen Sie die Zustellung ab, wenn
tmehr als 300 Sekunden von Ihrer Uhrzeit abweicht: Es handelt sich um einen Replay. - Berechnen Sie
HMAC-SHA256(secret, "<t>.<roher Body>")in Hexadezimal. - Akzeptieren Sie, wenn das Ergebnis mit einem beliebigen der
v1-Werte übereinstimmt, und vergleichen Sie dabei in konstanter Zeit.
import { createHmac, timingSafeEqual } from 'node:crypto';
export function verifyCordSignature(rawBody, header, secret, toleranceSec = 300) {
if (!header) return false;
let t = null;
const signatures = [];
for (const part of header.split(',')) {
const i = part.indexOf('=');
if (i < 0) continue;
const k = part.slice(0, i).trim();
const v = part.slice(i + 1).trim();
if (k === 't' && /^\d+$/.test(v)) t = Number(v);
else if (k === 'v1' && /^[0-9a-f]{64}$/i.test(v)) signatures.push(Buffer.from(v, 'hex'));
}
if (t === null || signatures.length === 0) return false;
if (Math.abs(Math.floor(Date.now() / 1000) - t) > toleranceSec) return false;
const expected = createHmac('sha256', secret).update(`${t}.`).update(rawBody).digest();
return signatures.some((s) => s.length === expected.length && timingSafeEqual(s, expected));
}
Mit Express fordern Sie den rohen Body nur auf dieser Route an:
import express from 'express';
import { verifyCordSignature } from './verify-cord.js';
const app = express();
app.post('/webhooks/cord', express.raw({ type: 'application/json' }), (req, res) => {
if (!verifyCordSignature(req.body, req.get('X-Cord-Signature-V1'), process.env.CORD_WEBHOOK_SECRET)) {
return res.sendStatus(400);
}
const event = JSON.parse(req.body);
// Vor jedem Nebeneffekt nach event.id deduplizieren.
res.sendStatus(200);
});
app.listen(3000);
Vergleichen Sie Signaturen in der Produktion nie von Hand mit === – verwenden Sie einen Vergleich in konstanter
Zeit (das SDK tut das bereits). Ein normales !== kann über einen Timing-Angriff Informationen preisgeben.
Das Testereignis ping
Die Schaltfläche Testen eines Endpoints in der Workbench sendet bei ausgewähltem ping (die Standardoption) eine Zustellung mit event: "ping" über denselben Weg wie ein echtes Ereignis (Signatur, Header und Protokoll). Sie verwendet Beispieldaten in der Form eines Angebots und ein Feld mensaje. Jeder Test trägt "test": true auf der obersten Ebene des Payloads:
{
"id": "evt_0b7e3d9a1c5f2e8b4a6d0c9f3e1b7a5d",
"event": "ping",
"created_at": "2026-10-07T17:12:09.441Z",
"test": true,
"data": {
"id": "00000000-0000-0000-0000-000000000000",
"folio": "COT-PRUEBA",
"status": "sent",
"moneda": "MXN",
"total": 12500,
"cliente": "Cliente de prueba S.A. de C.V.",
"cliente_id": null,
"link_publico": "https://cordhq.app/q/demo",
"mensaje": "Esta es una entrega de prueba enviada desde el Workbench de Cord."
}
}
Statt ping können Sie jedes Ereignis wählen, das der Endpoint abonniert hat: Es kommt mit seinem echten Typ an, mit Beispieldaten in der API-Version des Endpoints und ebenfalls mit "test": true. Ein Test wird nur einmal versucht: Schlägt er fehl, kommt er nicht in den Wiederholungsplan. Tests erscheinen nicht im Ereignisverlauf und lösen keine Workflows aus. Antworten Sie mit 2xx und verwerfen Sie sie. Um mit einem der 41 echten Ereignisse und den Daten eines Testobjekts zu testen, verwenden Sie den Webhook-Simulator oder cord trigger aus der CLI.
Identität des Ereignisses und Idempotenz
Jedes logische Ereignis hat eine stabile id (evt_…), identisch im Body und in X-Cord-Event-Id/Idempotency-Key. Es ist derselbe Wert:
- Bei jeder automatischen Wiederholung desselben Ereignisses (siehe nächster Abschnitt).
- Bei einem manuellen Replay aus der Workbench („Erneut versuchen“ im Zustellprotokoll) – der Payload wird Byte für Byte identisch erneut gesendet, einschließlich der
id.
Da Wiederholungen und Replays dazu führen können, dass Ihr Endpoint dasselbe Ereignis mehr als einmal erhält, muss Ihr Handler idempotent sein: Speichern Sie die bereits verarbeiteten id (und sei es in einer einfachen Tabelle mit unique) und verwerfen Sie Wiederholungen stillschweigend, bevor Sie Nebeneffekte ausführen (eine Zahlung einziehen, eine E-Mail senden usw.).
Wiederholungen und garantierte Zustellung
Cord stellt jedes Ereignis vor dem ersten Zustellversuch in eine Warteschlange – ist Ihr Endpoint nicht erreichbar, geht das Ereignis nicht verloren: Es folgt einem Wiederholungsplan mit exponentiellem Backoff von bis zu 11 Versuchen über ca. 3,6 Tage:
| Versuch | Wartezeit seit dem vorherigen |
|---|---|
| 1 | sofort |
| 2 | ca. 10 s |
| 3 | ca. 1 min |
| 4 | ca. 5 min |
| 5 | ca. 30 min |
| 6 | ca. 2 h |
| 7 | ca. 5 h |
| 8 | ca. 10 h |
| 9–11 | ca. 1 Tag |
(Mit einem Jitter von ±20 %, damit viele gleichzeitig ausgefallene Endpoints die Wiederholung nicht exakt in derselben Sekunde erhalten.) Jede Antwort außer 2xx, ein Netzwerkfehler oder keine Antwort innerhalb von 5 Sekunden gilt als Fehlschlag und plant den nächsten Versuch. Antworten Sie schnell und verarbeiten Sie später: Speichern Sie das Ereignis und antworten Sie mit 200, bevor Sie aufwendige Arbeit erledigen. Einem 3xx (Weiterleitung) wird nie gefolgt – es gilt als Fehlschlag; hat sich die URL Ihres Endpoints geändert, aktualisieren Sie sie in der Workbench, statt eine Weiterleitung einzurichten.
Die Zeiten in der Tabelle sind Mindestwerte
Der erste Versuch erfolgt im Moment des Ereignisses. Die Wiederholungen führt ein Durchlauf der Zustelllogik aus, der alle 5 Minuten läuft; jede Wiederholung erfolgt also beim ersten Durchlauf nach der Zeit, die die Tabelle angibt. War Ihr Endpoint nicht erreichbar, warten Sie nicht auf die nächste Wiederholung: Holen Sie Verpasstes über den Ereignisverlauf nach.
Die Zustellung erfolgt mindestens einmal (at-least-once), nicht genau einmal – deshalb ist die Deduplizierung nach id so wichtig (siehe oben).
Zustand des Endpoints
Cord überwacht die Serie von Fehlschlägen jedes Endpoints (gezählt werden nur Ereignisse, die ihren Wiederholungsplan ausgeschöpft haben, oder fehlgeschlagene manuelle Tests/Replays – nie ein Versuch, dem noch Wiederholungen bevorstehen):
- 3 Fehlschläge in Folge → Sie erhalten eine Warn-E-Mail (höchstens eine alle 24 h).
- 5 Fehlschläge in Folge → der Endpoint wird automatisch deaktiviert (er erhält keine neuen Ereignisse mehr), und Sie erhalten eine E-Mail mit der Begründung. Ereignisse, die für diesen Endpoint noch auf eine Wiederholung warteten, werden abgebrochen – sie stauen sich nicht endlos gegen ein nicht erreichbares Ziel.
Beide E-Mails gehen an den Inhaber des Kontos, in der Sprache Ihres Kontos (Einstellungen › Allgemein).
Sobald Sie Ihren Endpoint repariert haben, können Sie im Tab Webhooks der Workbench:
- Reaktivieren – ab sofort wieder neue Ereignisse empfangen.
- Reaktivieren und wiederholen – zusätzlich wird erneut eingereiht, was in den letzten 24 Stunden fehlgeschlagen ist (nie der gesamte Rückstand, damit Sie nicht auf einen Schlag mit alten Ereignissen überflutet werden).
Secret-Rotation
Sie können das Secret eines Endpoints rotieren, ohne eine einzige Zustellung zu verlieren. Klicken Sie in der Workbench auf „Secret rotieren“, wählen Sie ein Überlappungsfenster (1 h / 24 h / 72 h) und bestätigen Sie – Sie sehen das neue Secret einmalig im Klartext.
Während des Fensters signiert Cord jede Zustellung gleichzeitig mit beiden Secrets:
X-Cord-Signature-V1: t=1732650000,v1=<hmac with the NEW secret>,v1=<hmac with the OLD secret>
Die Reihenfolge ist fest: Das v1= des neuen Secrets steht zuerst, das des alten am Ende. So können Sie Ihr CORD_WEBHOOK_SECRET zu jedem Zeitpunkt innerhalb des Fensters aktualisieren, ohne dass eine Zustellung abgelehnt wird – vorausgesetzt, Ihre Verifizierung vergleicht alle v1= im Header. Das SDK akzeptiert bereits jedes der beiden, das passt. Wenn Sie von Hand verifizieren, behalten Sie nicht nur einen einzigen Wert: Wer nur den ersten liest, muss das neue Secret bereits haben, und ein Parser, der das letzte v1= behält (zum Beispiel einer, der eine Schlüssel-Wert-Map aufbaut), validiert während des Fensters nur mit dem alten Secret und schlägt daher fehl, sobald Sie vor Ende des Fensters auf das neue wechseln.
Die Legacy-Signatur X-Cord-Signature fasst nur einen Wert, daher wird sie während des Fensters mit dem alten Secret berechnet; nach dem Ende des Fensters wird sie mit dem neuen signiert. Sobald das Fenster endet, signiert Cord in beiden Headern nicht mehr mit dem alten Secret.
Ereigniskatalog
| Ereignis | Wird ausgelöst, wenn… |
|---|---|
quote.sent |
Der Verkäufer das Angebot an den Kunden sendet. |
quote.viewed |
Der Kunde den öffentlichen Link zum ersten Mal öffnet. |
quote.approved |
Der Kunde das Angebot (ganz oder teilweise) bestätigt. |
quote.rejected |
Der Kunde es ablehnt. |
quote.updated |
Der Verkäufer es ändert und erneut sendet („Ändern und erneut senden“ in der Detailansicht). |
quote.expired |
Seine Gültigkeit abgelaufen ist, ohne dass der Kunde entschieden hat (es war sent/viewed). |
quote.deleted |
Ein Entwurf gelöscht wird (gilt nur für Angebote, die nie gesendet wurden). |
quote.paid |
Die vollständige Zahlung eingeht (eine einfache Zahlung oder die letzte ausstehende Zahlung eines Plans mit Anzahlung oder Raten). |
payment.partial |
EINE Teilzahlung eingeht (Anzahlung, Restzahlung oder eine Rate), ohne dass das Angebot bereits vollständig bezahlt ist. |
payment.failed |
Eine wiederkehrende Zahlung einer Monatspauschale fehlschlägt. |
invoice.stamped |
Der CFDI gestempelt wird (stammt aus einem Angebot, siehe Hinweis unten). |
invoice.issued |
Außerhalb Mexikos eine Rechnung ausgestellt wird (stammt aus einem Angebot). |
invoice.finalized |
Eine Rechnung von Cord Invoicing ausgestellt wird – das eigenständige Rechnungsobjekt, nicht an ein Angebot gebunden. |
invoice.sent |
Der Verkäufer diese Rechnung an den Kunden sendet. |
invoice.paid |
Die Rechnung vollständig bezahlt ist. |
invoice.payment_failed |
Eine Zahlung auf diese Rechnung fehlschlägt (abgelehnte Karte, fehlgeschlagene Lastschrift). |
invoice.voided |
Die Rechnung storniert wird. |
invoice.marked_uncollectible |
Die Rechnung als uneinbringlich markiert wird. |
invoice.overdue |
Ihr Fälligkeitsdatum verstrichen ist, ohne dass sie beglichen wurde (ausgelöst durch den Cron der Zahlungserinnerungen). |
quote.created |
Ein Angebot erstellt wird, in der App, über die API, über MCP oder über Cord Elements. |
quote.approval_requested |
Ein neues Angebot auf eine interne Freigabe wartet (Rabatt, Betrag oder Marge außerhalb des Schwellenwerts). Enthält motivo. |
quote.approval_decided |
Die Geschäftsleitung diese Anfrage freigibt oder ablehnt. Enthält decision (approved | rejected). |
quote.comment_added |
Der Kunde oder der Verkäufer in der Unterhaltung des Angebots schreibt. Enthält autor (cliente | vendedor), mensaje und, wenn es sich auf eine Position bezieht, item_id; ein Gegenangebot enthält tipo: "contraoferta" und propuesta. |
client.created / client.updated / client.deleted |
Ein Kunde im Verzeichnis angelegt, bearbeitet oder gelöscht wird. |
product.created / product.updated / product.deleted |
Ein Produkt im Katalog angelegt, bearbeitet oder gelöscht wird. |
task.created / task.completed |
Eine Aufgabe erstellt wird (in der App, über die API, über MCP, durch einen Workflow oder durch Cord wegen einer Rückbuchung oder einer SPEI-Rückerstattung) oder als erledigt markiert wird. |
promise.created / promise.kept / promise.broken |
Eine Zahlungszusage erfasst oder als eingehalten bzw. nicht eingehalten markiert wird. |
dispute.created / dispute.closed |
Ein Kunde eine Rückbuchung zu einer Zahlung über Cord Payments einleitet oder sie mit ihrem Ergebnis in estado abgeschlossen wird (won | lost | warning_closed). Enthält monto, moneda, motivo und fecha_limite für die Antwort. |
refund.succeeded / refund.failed |
Eine Rückerstattung abgeschlossen wird oder fehlschlägt. Enthält monto, moneda, motivo und bei einem Fehlschlag motivo_falla. |
payout.paid / payout.failed |
Eine Auszahlung auf Ihr Bankkonto ausgeführt wird oder fehlschlägt. Enthält monto, moneda, llegada und bei einem Fehlschlag motivo_falla. |
account.updated |
Sich ändert, was Ihr Zahlungskonto kann: puede_cobrar, puede_depositar, pendientes (noch zu verifizierende Daten) und motivo_bloqueo. Wird nur gesendet, wenn sich einer dieser Werte ändert. |
ping |
Erscheint nur bei „Testen“ in der Workbench – wird nie durch ein echtes Ereignis ausgelöst. |
Die Ereignisse zu Rückbuchungen, Rückerstattungen und Auszahlungen enthalten
referencia, die Kennung des Vorgangs beim Zahlungsdienstleister, und werden pro Vorgang und Ergebnis nur einmal gesendet. Stammt die Zahlung aus einem Angebot, enthalten sie außerdemcotizacion_id,folioundcliente.
Hinweis:
payment.partialenthält indatazusätzliche Felder, die die übrigen Angebots-Ereignisse nicht haben:tipo(anticipo|saldo|cuota),monto,numero_cuota,saldo_pendienteundpayment_method, zusätzlich zur normalen Zusammenfassung des Angebots (Nummer, Kunde, Gesamtbetrag, Link).
Zwei Ereignisfamilien, zwei Formen von data. Die Ereignisse quote.* und payment.* (einschließlich
invoice.stamped/invoice.issued, die aus dem Angebot ausgelöst werden) teilen die Form von data aus dem
Beispiel oben (folio, status, total, cliente, link_publico…). Die sieben Ereignisse
invoice.finalized/sent/paid/payment_failed/voided/marked_uncollectible/overdue
gehören zu Cord Invoicing – die Rechnung als eigenes Objekt, mit eigenem Lebenszyklus und eigenem
öffentlichen Link, nicht als Ableitung eines Angebots – und haben eine ANDERE Form von data:
{
"id": "evt_7c3e9a1f5b2d8e4a0c6f3b9d1e7a5c2f",
"event": "invoice.paid",
"created_at": "2026-08-20T14:00:00.000Z",
"data": {
"id": "d4a1b3c5-7e9f-4a2b-8c4d-6e8f0a2b4c6d",
"object": "invoice",
"numero": "FAC-0032",
"folio_fiscal": "3F2A9C1E-7B4D-4E6A-8C2F-1D5B9E3A7C40",
"estado": "paid",
"estado_fiscal": "issued",
"pais": "MX",
"tipo": "cfdi_40",
"moneda": "MXN",
"total": 12500.00,
"pagado": 12500.00,
"saldo": 0,
"vence": "2026-08-30",
"cliente": "Distribuidora El Zarco",
"cotizacion_id": null,
"link_publico": "https://cordhq.app/i/9c1f4e7a2b5d8c0f3a6e9b2d5f8a1c4e"
}
}estado ist der Lebenszyklus der Rechnung (draft, open, paid, void oder uncollectible).
estado_fiscal ist die Registrierung beim steuerlichen Anbieter: pending, issued, cancelled oder
error. tipo ist der Dokumenttyp: cfdi_40, cfdi_egreso, proforma, commercial_invoice,
commercial_credit_note, verifactu_invoice oder verifactu_credit_note.
Achten Sie auf den öffentlichen Link: /i/{token} für eine Rechnung von Cord Invoicing, dagegen /q/{token}
für ein Angebot. Wenn Sie @flouviahq/node mit TypeScript verwenden, gibt constructEvent den Typ
CordWebhookEvent zurück, eine nach event unterschiedene Union, die bereits alle 41 Ereignisse des Katalogs
typisiert, einschließlich der sieben invoice.* von Cord Invoicing mit der Form oben.
Form von data bei Kunden, Produkten, Aufgaben und Zahlungszusagen
Jedes Objekt enthält object, damit Sie es unterscheiden können. Das Produktereignis enthält nie Kosten oder Marge.
object |
Felder |
|---|---|
client |
id, empresa, contacto, email, telefono, rfc, terminos, country_code, language (seine Dokumentsprache; null = die der Organisation) (bei client.deleted: nur id und empresa) |
product |
id, sku, nombre, unidad, precio_lista, activo (bei product.deleted: nur id und nombre) |
task |
id, titulo, due_date, done, cotizacion_id (ohne zuständige Person, Priorität und Notizen) |
promise |
id, cotizacion_id, fecha_promesa, monto, moneda, estado |
Endpoints über die API verwalten
Plattformen wie Zapier oder Make erstellen und löschen ihre Abonnements selbst. Dafür gibt es diese Routen:
| Methode und Route | Scope | Was sie tut |
|---|---|---|
GET /api/v1/webhooks |
read |
Listet die Endpoints auf, die genau dieser Schlüssel erstellt hat, ohne Secrets. |
POST /api/v1/webhooks |
write |
Erstellt einen Endpoint. Body: { "url": "https://…", "eventos": ["quote.approved"] }. Gibt id, url, eventos und secret zurück (nur einmal im Klartext). |
DELETE /api/v1/webhooks/{id} |
write |
Löscht einen Endpoint, den genau dieser Schlüssel erstellt hat. |
Es gelten dieselben URL-Regeln wie in der Workbench: nur https:// zu öffentlichen Hosts. Diese Abonnements zählen nicht gegen die Endpoints Ihres Teams: Sie haben ein eigenes Kontingent von 100 pro Organisation (integration_limit_reached).
Ein Schlüssel kann die in der Workbench oder von einem anderen Schlüssel erstellten Endpoints weder sehen noch löschen. Wenn Sie einen Schlüssel widerrufen, werden seine Endpoints deaktiviert: Wenn Sie eine Integration trennen, erhält sie keine Daten mehr.
Ereignisverlauf über die API
War Ihr System länger nicht erreichbar, als die Wiederholungen abdecken, oder fragen Sie lieber ab, statt zu empfangen, gibt GET /api/v1/events (Scope read) die Ereignisse Ihrer Organisation vom neuesten zum ältesten zurück, unabhängig davon, ob Endpoints abonniert sind:
curl "https://cordhq.app/api/v1/events?type=quote.approved&limit=50" \
-H "Authorization: Bearer sk_live_tU..."
{
"data": [
{
"id": "6b0e2f4a-8c1d-4e3b-9a5f-7d2c0e8b1a46",
"type": "quote.approved",
"object": "quote",
"object_id": "b3f1c2d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
"data": { "id": "b3f1c2d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d", "folio": "COT-0148", "status": "approved", "moneda": "MXN", "total": 45200 },
"actor": "client",
"created_at": "2026-09-14T18:32:04.123Z"
}
],
"meta": { "next_cursor": "MjAyNi0wOS0xNFQxODozMjowNC4xMjMwMDBafDZiMGUyZjRhLThjMWQtNGUzYi05YTVmLTdkMmMwZThiMWE0Ng" }
}
- Optionale Filter:
type(ein Ereignis aus dem Katalog) undobject_id. next_cursorist ein undurchsichtiges Token: Wiederholen Sie die Anfrage mit?cursor=<next_cursor>. Es istnull, wenn es keine weiteren Seiten gibt.actorgibt an, wer das Ereignis ausgelöst hat:user:<id>,api:<key>,mcp:<key>,client(der Kunde im öffentlichen Link),workflow:<id>,systemund weitere. Siehe die vollständige Liste.- Die
idim Verlauf ist die UUID des Datensatzes, nicht dasselbe wie dasevt_…des Webhooks. - Anders als beim Webhook enthält
datakeinlink_publico: Der Link ist ein Zugangsnachweis und wird nicht im Verlauf gespeichert.
Zustellprotokoll und Aufbewahrung
Im Tab Webhooks der Workbench hat jeder Endpoint ein aufklappbares Protokoll mit seinen letzten 50 Zustellungen (Ereignis, Versuch, Status, Dauer und Datum). Jede lässt sich öffnen und zeigt, was Cord gesendet hat (den exakten Payload), was Ihr Server geantwortet hat und die Schaltfläche Erneut versuchen. Der Tab Ereignisse der Workbench zeigt dasselbe aus einem anderen Blickwinkel: ein logisches Ereignis mit seiner Zustellung an jeden Endpoint statt eines Protokolls pro Endpoint, und die Schaltfläche Erneut senden. Das Protokoll wird 30 Tage aufbewahrt; endgültig fehlgeschlagene Ereignisse 90 Tage (damit „Erneut versuchen“ in diesem Fall länger funktioniert). Nutzen Sie das Protokoll von Cord nicht als Langzeitspeicher für Gesendetes – speichern Sie, was Sie aufbewahren müssen, bei der Verarbeitung in Ihrem eigenen System.
Das Zustellprotokoll einsehen, eine Zustellung erneut versuchen, ein Ereignis erneut senden und einen Endpoint reaktivieren und wiederholen erfordern den Professional-Tarif oder höher. Endpoints erstellen, Ereignisse empfangen, Testen, Secret rotieren und Reaktivieren sind in allen Tarifen verfügbar.