Zum Inhalt springen

Webhooks

Instead of you polling regularly, DebtFlow sends you an HTTP request as soon as something happens: invoice paid, letter delivered, debt moved to a new phase.

Setting up an endpoint

You create webhook endpoints in the dashboard under Settings → Webhooks or via the API with POST /webhook-endpoints (scope webhooks:write). You specify an https:// URL and the events you want. When the endpoint is created, you receive its signing secret once – keep it safe like a password.

curl -X POST 'https://www.debt-flow.io/api/v1/webhook-endpoints' \
  -H "Authorization: Bearer $DEBTFLOW_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
  "url": "https://example.com/webhooks/debtflow",
  "events": [
    "invoice.paid",
    "debt.phase_changed"
  ]
}'

The exact fields are listed in the API reference in the Webhooks section.

Structure of a delivery

Request to your server
POST /webhooks/debtflow HTTP/1.1
Content-Type: application/json
DebtFlow-Event-Id: evt_3kR9xY2mQ7pL0aB4cD1e
DebtFlow-Signature: t=1762248600,v1=5f2b0c…

{
  "id": "evt_3kR9xY2mQ7pL0aB4cD1e",
  "object": "event",
  "type": "invoice.paid",
  "apiVersion": "2026-11-01",
  "createdAt": "2026-11-04T09:30:00.000Z",
  "data": {
    "object": { "id": "…", "status": "paid", "…": "…" }
  }
}
  • data.object is the resource in the same format the REST API returns. For *.updated, data.previous shows which fields changed and how.
  • id and the DebtFlow-Event-Id header are unique per event. An event can arrive more than once – store processed IDs and skip repeats.
  • The order of delivery is not guaranteed. createdAt is authoritative.

Verifying the signature

Every delivery is signed with the endpoint's secret. The DebtFlow-Signature header contains a timestamp t (Unix seconds) and the signature v1:

Header
DebtFlow-Signature: t=1762248600,v1=5f2b0c9e…
  1. Build the string: t, a dot, then the unmodified request body.
  2. Compute HMAC-SHA256 with the secret and encode it as hexadecimal (lower case).
  3. Compare it in constant time with every v1 value.
  4. Reject deliveries whose t differs from your clock by more than 5 minutes – this prevents old requests from being replayed.
# Generate a signature yourself and test your own endpoint
BODY='{"id":"evt_test","object":"event","type":"webhook.test","apiVersion":"2026-11-01","createdAt":"2026-11-04T09:30:00.000Z","data":{"object":{}}}'
T=$(date +%s)
SIG=$(printf '%s.%s' "$T" "$BODY" | openssl dgst -sha256 -hmac "$DEBTFLOW_WEBHOOK_SECRET" -hex | sed 's/^.* //')

curl -X POST 'https://example.com/webhooks/debtflow' \
  -H 'Content-Type: application/json' \
  -H "DebtFlow-Signature: t=$T,v1=$SIG" \
  -d "$BODY"
Most common mistake
The signature applies to the bytes DebtFlow sent. If the body is parsed as JSON and re-serialised first (whitespace, order, special characters), it no longer matches. Read the raw body.

Responses and retries

  • Respond with a 2xx status as soon as the signature is valid, and process the event asynchronously afterwards. Long processing within the request leads to timeouts and retries.
  • On errors or without a response, DebtFlow retries the delivery at increasing intervals for up to three days.
  • If delivery to an endpoint fails permanently, the endpoint is deactivated. You can see this in the settings and reactivate it there.
  • An endpoint only receives events for which the API key or app that created it has the listed scope.

Events

EventMeaningScope
contact.createdContact createdcontacts:read
contact.updatedContact updatedcontacts:read
contact.deletedContact deletedcontacts:read
communication.createdCommunication with a contact loggedcontacts:read
debt.createdDebt createddebts:read
debt.updatedDebt updateddebts:read
debt.phase_changedDebt moves to another phase (dunning, court, enforcement …)debts:read
debt.overdueDebt has become overdue (once per due date)debts:read
debt.paidDebt paid in fulldebts:read
debt.deletedDebt deleteddebts:read
payment.receivedPayment recorded for a debtpayments:read
payment.deletedPayment deletedpayments:read
installment_plan.createdInstalment plan createdpayments:read
installment_plan.updatedInstalment plan updated (amount, instalments, status)payments:read
installment_plan.deletedInstalment plan deletedpayments:read
installment.dueInstalment falls due within the next 3 days (once per instalment)payments:read
installment.missedInstalment not paid by its due date (once per instalment)payments:read
residence_registry_inquiry.createdResidents’ registration office request ordered (paid)research:read
recommendation.createdCreditor AI recommendation createdai:read
letter.sentLetter handed over to the print serviceletters:read
letter.deliveredLetter deliveredletters:read
letter.returnedLetter returned as undeliverableletters:read
letter.failedLetter dispatch failedletters:read
invoice.createdDraft invoice createdinvoices:read
invoice.updatedDraft invoice updatedinvoices:read
invoice.finalizedInvoice finalised (number assigned)invoices:read
invoice.sentInvoice sent (email or post)invoices:read
invoice.partially_paidPartial payment on an invoiceinvoices:read
invoice.paidInvoice paid in fullinvoices:read
invoice.overdueInvoice overdueinvoices:read
invoice.canceledInvoice cancelledinvoices:read
invoice.deletedDraft invoice deletedinvoices:read
invoice.handed_to_collectionInvoice handed over to dunning (debt created)invoices:read
credit_note.finalizedCredit note or cancellation invoice finalisedinvoices:read
offer.createdQuote createdoffers:read
offer.sentQuote sentoffers:read
offer.acceptedQuote acceptedoffers:read
offer.rejectedQuote rejectedoffers:read
offer.expiredQuote expiredoffers:read
offer.convertedQuote converted into an invoice or order confirmationoffers:read
receipt.createdReceipt uploaded or receivedreceipts:read
receipt.processedOCR completedreceipts:read
receipt.updatedReceipt updatedreceipts:read
receipt.bookedReceipt finalisedreceipts:read
receipt.deletedReceipt deletedreceipts:read
bank_transaction.importedBank transaction importedbanking:read
bank_transaction.matchedBank transaction matched to a receipt or invoicebanking:read
project.createdProject createdprojects:read
project.updatedProject updatedprojects:read
project.archivedProject archivedprojects:read
project.deletedProject deleted (only without time entries)projects:read
time_entry.createdTime entry recordedtime:read
time_entry.updatedTime entry updatedtime:read
time_entry.deletedTime entry deletedtime:read
export.readyExport (e.g. DATEV) ready for downloadreports:read
accounting_period.closedAccounting period locked (GoBD)accounting:read
webhook.testTest event from the webhook settingswebhooks:read

The schemas of all events are also listed in the webhooks section of the OpenAPI description.