Skip to main content

Outcome

You have a validated, immutable submitted order and retained identifiers for the order and its claims. You can then wait for a client request, rejection, withdrawal, or acceptance into a mandate. This workflow covers the standard invoice submission and uses ReceivableClaim entries, each declaring the required claim "type": "receivable". Omitting the order-level type defaults to invoice. For subtype resources and readiness rules, use Submit a rental order or Submit a titled order.

Prerequisites

  • A production or sandbox base URL and Bearer key.
  • An entitled company UUID on every call when using a Partner key.
  • A debtor UUID with sufficient address and notification data.
  • One stable Idempotency-Key per logical POST command.

Lifecycle context

Only draft orders are editable and finalizable. Finalize has no body and makes the aggregate immutable with public state submitted, including during internal review. Acceptance creates or extends a mandate and freezes the legal debtor snapshot. A submitted order may be withdrawn only before staff review starts.

0. Create or reuse the debtor

Create the reusable debtor first. Each example parses the exact returned UUID; persist it as DEBTOR_ID and use that value in the order request. Reconcile an ambiguous retry by the exact your_reference; never guess an ID.

1. Create an aggregate draft

This invoice-order payload references one existing debtor UUID, up to 10 additional debtor UUIDs, and up to 50 ReceivableClaim entries. Do not send calculated total fields, interest configuration, rental-agreement or enforceable-title fields, or order_flow_type. Create or update debtor details only through the debtor resource. Order writes contain debtor UUIDs, never debtor objects. Create new claims inline as complete claim request objects, or attach them to a draft through the stable claim collection shown below. Every claim needs a default date (delay_date) before finalization. Send it explicitly as above, or let the API derive it: from the claim’s reminders for a consumer debtor, or from document_date plus 32 days for a business debtor. A consumer claim with neither delay_date nor reminders stays a draft — finalization reports claims.<id>.delay_date as missing.

Staged claim alternative

Create the empty draft first, then use a distinct stable idempotency key for this logical claim command. Preserve the exact key and body for replay, and store the returned claim UUID after verifying its exact business reference.

2. Correct the draft

Patch only what changed. To change the additional debtors, send additional_debtor_ids to PATCH /v2/orders/{id}/. The array replaces the complete membership: include the UUID of every debtor you want to keep. Omit the field to preserve the membership; [] unlinks everyone without deleting debtor records. The same 10-debtor limit and duplicate checks apply as at creation. This operation is available only while the order is a draft. Existing debtor and claim data remain unchanged on unrelated patches. Patch a draft claim by its stable top-level claim UUID; replacing a claim’s complete additional_charges array requires every desired replacement charge. The order response embeds debtor summaries. Use their IDs with GET /v2/debtors/{id}/ for full details, and PATCH /v2/debtors/{id}/ to correct debtor information. When updating membership based on a previous order read, send its ETag in If-Match to avoid overwriting a concurrent edit. For a claim correction, patch the stable top-level claim resource directly:

3. Finalize without a request body

Finalize accepts an empty body or exactly {}; the cURL example uses the empty form, so it sends neither --data nor Content-Type. After a timeout, fetch the order by ID first. Record any observed submitted, awaiting_client_response, accepted, rejected, withdrawn, or expired outcome. If it is still draft, make an explicit retry decision with the same FINALIZE_KEY; never issue a second uncontrolled finalize write.

Representative response

This is a complete response matching the Order response schema.

Runnable Python workflow

This orchestration proves the sandbox before any write, uses one generated key per logical POST, and never automatically repeats an ambiguous finalize call.
Python workflow

Failure and recovery

  • 400 validation_error: correct the reported field paths on the draft, then finalize again with a new logical-command key. The failed validation did not finalize the order. Common causes on create and PATCH: a missing debtor_id (debtor_id / required), a non-string, malformed, or empty UUID (debtor_id / invalid, or additional_debtor_ids[i] / invalid), a duplicate party (additional_debtor_ids / duplicate), creditor_obligation_fulfilled or is_disputed sent as a string or number instead of a JSON boolean (invalid), a date with non-ASCII digits (invalid), or a control character in a text field (control_characters). An unknown or other-company debtor UUID is a neutral 404, not a 400 field error.
  • 403 terms_acceptance_required on finalize: the credential’s current API terms have not been accepted. Accept them in the developer portal; the draft stays editable and finalize again with a fresh key.
  • Finalize timeout, transient 500, or 503: fetch the exact order by ID before making any retry decision. Record every valid non-draft lifecycle outcome; only an observed draft can be considered for an explicit retry with the same key. Do not immediately repeat finalize.
  • For other ambiguous idempotent POST outcomes, reconcile the resource first; if a retry is still required, repeat the same request with the same key.
  • 409 idempotency_request_in_progress: wait for Retry-After, then retry the same request and key. idempotency_key_expired is terminal; reconcile by fetching the order. Reusing a key for a different operation or body also returns 409 and requires a new logical command.
  • Lifecycle 409: refetch the order. It may already be finalized (Order is already finalized.), withdrawn or decided (Order is already finalized or withdrawn. — also when finalize raced a withdrawal), or merged into another order (Order was merged into another order., on every write; follow merged_into). Another actor may have changed it.
  • To withdraw an eligible submitted order, use a fresh command key:
Withdrawal returns 409 after staff review starts and for draft, accepted, rejected, expired, or already withdrawn orders. Refetch and stop; do not loop.

Verify

Then require .status to be submitted or accepted before recording the workflow as successful. Also retain X-Paywise-Request-Id for support and the finalization key until the outcome is durably recorded.

Reconcile acceptance by claim UUID

Webhook deliveries are at least once. On order.accepted, intersect the event’s claim_ids with the claim UUIDs stored by exact business reference. For every match, refetch /v2/claims/{claim_id}/ and trust the claim’s current order_id and mandate_id, even when the event order differs from the originally submitted order. The claim UUID remains stable; do not scan orders or reconstruct merge chains.