https://api-sandbox.paywise.de directly; replace
the inline PAYWISE_API_KEY placeholder with a sandbox key (pw_sbx_…)
created in the developer portal. Other language tabs read the matching
environment variables.
The request tabs below are complete, copyable examples for individual
operations. The final section runs the whole flow end to end once in Python.
There is no Idempotency-Key header on this API: submitting an invoice is
idempotent on its invoice_number (per company and environment), so a repeat
submission returns 200 with the existing invoice instead of creating a
duplicate.
Before you start: save a sandbox Mahnlauf
Mahnservice configuration is sandbox-native and is not copied from production. Company profile, the entering user’s membership, company-level notification recipients, and that user’s own notification recipients are mirrored; a synthetic sandbox entitlement is granted independently of a production purchase. Enter the sandbox from the production portal under Für Entwickler → Zur Sandbox, then open Mahnservice → Erste Schritte → Mahnlauf einrichten. Configure the flow, proceed to step 4 (Speichern), and choose Mahnlauf speichern. The sandbox saves a default flow without checkout, a paid subscription or a SEPA mandate. Bookkeeping integration is unnecessary; this API supplies the invoices. Saving creates the default configuration; activation is a separate step. Choose Weiter to return to Erste Schritte, then Mahnlauf prüfen und aktivieren when the page shows Alles bereit!. This starts the sandbox ladder; outbound notices are captured in the E-Mail-Log instead of delivered. Until you activate the flow in the portal, API release creates apending
dunning process. GET /mahnservice/v1/dunning-flows/ lets you inspect the
configuration. If release reports 409 no_default_dunning_flow, complete the
wizard in the same sandbox company as your key.
In production, the wizard also saves the configuration before opening
Weiter zur Zahlung. Abandoning checkout keeps the flow so checkout can be
resumed through Abo abschließen on Erste Schritte, but a payment method and an active subscription are still required
for production use. Sandbox setup does not change production billing.
1. Find or create the debtor
Creating a debtor is not idempotent — a repeat call creates a second debtor row. Keep the returnedid in your own customer record. If it is missing,
look up your customer before creating another:
cURL lookup
customer_number is an exact, case-sensitive match; email is an exact,
case-insensitive match against the debtor’s displayed email. If you supply
both, they are combined with AND. Results stay scoped to your company and
credential’s data lane and use normal count, next and results pagination.
Omit an unused filter; blank or whitespace-only values, customer numbers over
50 characters and malformed email values return 400 with the field name.
Surrounding whitespace is trimmed from customer_number on lookup exactly as
it is on create, so a padded lookup still finds the row you created.
Reuse a matching debtor only after checking its identity. These fields are
not unique: multiple matches need reconciliation, and a lookup followed by a
create cannot prevent two concurrent workers creating duplicates. Serialize
creation per customer in your integration and store the resulting id. The
create examples below apply when there is no existing match.
id directly — read it from the
201 body.
2. Submit the invoice
The invoice is created held: recorded and visible, but not dunned, and no dunning process exists yet. Use a freshinvoice_number for a new claim; a
repeat submission of the same number returns 200 with the existing invoice
and ignores every changed field. To fix wrong data while the invoice is held,
use PATCH /mahnservice/v1/invoices/{uuid}/ instead of inventing a second
number.
201 means a new invoice was created; 200 means this invoice_number was
already submitted and the existing invoice was returned unchanged. Read the
invoice’s id from the body — dunning_state is held.
3. Attach the invoice PDF and wait for scanning
If you want the original PDF enclosed with the notices, upload it while the invoice is held. The invoice documents guide shows the multipart request and the response shape.POST .../documents/
returns 201 with a document id and status: "pending"; it does not return
an invoice. Poll GET .../documents/{document_uuid}/ until ready before
releasing. Stop on rejected or failed, and upload a corrected replacement
while held. Release returns 409 document_not_ready while an attached
document is not ready. An invoice without an attachment can also be released.
The complete Python example below includes the upload and a bounded poll.
4. Release the invoice for dunning
Release declares no request body. It creates the dunning process and is the moment paywise starts writing to the debtor. The process startsactive when
the company’s Mahnlauf is activated, pending until then. Release is
idempotent — a second call returns the current state.
5. Read the dunning state
The dunning projection shows the state, the current level, the next action date, the configured flow, and the history of sent notices with their fees.POST /mahnservice/v1/invoices/{uuid}/payments/), or end the claim with
cancel or write-off. When the debtor never pays, the dunning ladder ends
in the handover to collection (dunning_state: "inkasso",
dunning.handed_to_collection). That handover needs no bookkeeping
integration: paywise builds the collection case from the invoice, debtor,
reported payments, and PDF you submitted here.
6. Runnable end-to-end workflow
Installrequests, replace the inline PAYWISE_API_KEY placeholder, and
set INVOICE_PDF_PATH to a real local PDF. Configure the sandbox Mahnlauf
first as described above. The program reuses a customer by customer_number,
uploads the PDF, and stops on a failed scan or after at most 60 polls. Each
run uses a fresh invoice number.
Python workflow
