Skip to main content
Take an ALLOW from Attesso and execute it on Mollie as a payment, then report the outcome. This is the Mollie recipe for the pattern in Bind an authorization to your PSP: authorize first, execute second, report finality. Attesso authorizes and records; your backend calls Mollie to execute, then reports the outcome to Attesso. Attesso never calls Mollie. API host: https://api.mollie.com/v2. Test mode uses a test_ API key and live uses live_ (or the testmode parameter with an organization access token); test and live data are fully isolated. Mollie’s test mode supports EUR only. New to Attesso? The quickstart covers creating a workspace, a test key, and the approval trust this recipe assumes.

Execute the approved action

Create the payment from the same immutable proposed action you sent to /authorizations; bind the two systems with your external_action_reference.
Keep the request derived from the authorized action: same amount, same currency, same reference. Mollie validates webhookUrl reachability at creation (a loopback URL is rejected); in local development point it at a public tunnel. The loop runs once per Authorization. Under a RECURRING mandate, every execution takes this same authorize, execute, report path, each one counted against the mandate’s per-period budget.

Report the outcome to Attesso

  • Definite acceptance (paid, or authorized for manually captured methods): commit with provider_transaction_reference: payment.id.
  • Definite non-acceptance (failed, expired, canceled): cancel with reason: EXECUTION_FAILED (use EXECUTOR_REJECTED when Mollie refuses the action outright). With an earlier ALLOW, the disposition is NO_LONGER_POSSIBLE.
  • A refund after commit is not an authorization transition; report it so the signed evidence carries the claim (Refund reports).
  • open, pending (or a still-open checkout): not final; do not commit or cancel yet.
  • A timeout or lost response: reconcile before deciding (below).

Webhooks

One rule covers both flows in this loop: a notification is a trigger, never the proof. From Mollie. Mollie posts only the payment id (form-encoded) to the webhookUrl you set on creation; fetch the payment yourself and act on its state. Respond 200 OK immediately, before processing. Mollie retries failed deliveries ten times over about 26 hours. From Attesso. Attesso delivers signed lifecycle notifications: mandate approvals and revocations, authorization outcomes, and the rest of the journal. Register an endpoint with Webhooks, verify every delivery, then fetch current state and the signed evidence bundle.

Reconcile a lost response

  • Retry the identical create call with the same Idempotency-Key: Mollie returns the original response (Idempotent-Replayed: true header); a 409 Conflict means the first request is still in flight; a reused key with different bytes is a 400.
  • Keys survive for one hour; after that the same key is a new request.
  • Find the payment by listing payments and matching your metadata values, or retrieve it directly by its tr_ id.
The full decision table is in Reconcile authorization outcomes.

Test mode

Verified against Mollie test mode (Oct 2026):
  • Selecting paid in the test checkout completes the payment and returns the payer to redirectUrl.
  • To exercise a failed payment, pin "method": "creditcard" at creation and use a documented magic amount from Mollie’s testing reference, for example 1007.00 -> insufficient_funds, then select Failed on the status screen. A payment created without a pinned method bounces non-paid selections back to method selection and stays open; open test payments are not cancelable via the API (DELETE /payments/{id} -> 422).
  • On paid test payments, Mollie adds a changePaymentState link for testing refunds and chargebacks.

Rehearsal

mollie-e2e.mjs drives the full loop against this recipe: Mandate create, passkey approval, an over-cap DENY, an in-cap ALLOW executed as a Mollie test payment, then commit (paid) or cancel (failed), with the signed evidence verified locally. Every create is replayed under its idempotency key first, and the replay must return the same resource. Settle each printed checkout URL in a browser; pass MOLLIE_WEBHOOK_URL (a public tunnel URL ending in /mollie-webhook) to exercise real webhook delivery, or leave it unset to settle by polling.
mollie-e2e-drive.mjs wraps the harness with Playwright: a virtual passkey for the approval, scripted checkout walks. node mollie-e2e-drive.mjs --runs 3 completes three full loops without a human at the keyboard. It needs Playwright installed.