Payment Flow
Understanding the payment lifecycle
Overview
A payment follows this lifecycle:
- Create a payment with amount, currency, and reference — the response carries a one-time
client_secret - Collect card details via the Hosted Fields SDK, which submits them against the
client_secret(the card never touches your server) - Authorize the payment (may require 3D Secure)
- Capture the funds (automatic or manual)
# Create a payment — returns a client_secret for the Hosted Fields SDK
curl -X POST https://api.settleflow.io/v2/payments \
-H "X-Api-Key: your_api_key" \
-H "Content-Type: application/json" \
-d '{ "amount": 1000, "currency": "EUR", "reference": "order-123", "capture_mode": "manual" }'
# → { "id": "pr_xxx", "status": "pending", "client_secret": "pr_xxx_secret_…", ... }Wallet / APM payments return a redirect_url instead of a client_secret — send the customer there to complete the payment.
redirect_url is always a URL on the API host, never the provider's own address: the customer lands on a short hand-off page that passes them to the provider. Follow it as-is — do not parse it or allow-list a destination domain from it. It is short-lived, so do not store it for later.
Pay by bank (open banking) works differently: payment_method.type: "pay_by_bank" always
returns the hosted_page_url of our payment form, where the customer picks their bank and is
redirected to approve the payment. The hosted page is locked to the requested method — the
customer completes a pay-by-bank payment by bank, never with a card. The bank list is not exposed
on this API — the hosted form is the selector. The final status arrives asynchronously (poll the
payment or use webhooks).
Hosted payment page & sessions
Instead of embedding the Hosted Fields SDK, you can create a payment session and redirect the customer to our hosted payment page (SAQ A):
curl -X POST https://api.settleflow.io/v2/payment-sessions \
-H "X-Api-Key: your_api_key" \
-H "Content-Type: application/json" \
-d '{ "amount": 1000, "currency": "EUR", "reference": "order-123" }'
# → { "id": "pr_xxx", "status": "pending",
# "client_secret": "pr_xxx_secret_…",
# "hosted_page_url": "https://pay.settleflow.io/pr_xxx?token=…",
# "expires_at": "2026-07-21T10:00:00.000Z", ... }Both surfaces share the same payment: client_secret drives the embedded Hosted Fields SDK, hosted_page_url is our full hosted page. Capture, void, refund and webhooks are identical to /v2/payments/{id}. A session is payable until expires_at (24h, or the link's own expiry when the session came from a payment link); a submit after that is rejected.
What the customer can pay with
The hosted page offers the payment methods your account is configured for, intersected with what the payment providers behind your routes can actually process — so a method is never offered unless a payment can complete on it. With only cards enabled the page shows the card form alone, and nothing changes.
Enable a wallet (Apple Pay, Google Pay) and the page adds it next to the card
form. The customer picks it, we hand them to the provider's wallet sheet, and
they come back to your return_url — no card data, and nothing to register or
certify on your side. The payment reads back through
GET /v2/transactions with method_family: "wallet" and the specific
method_type, so wallet volume is filterable like any other.
You do not choose the method when you create a session: the customer does, on the page. Ask your account manager to enable a wallet — it needs a provider on your account that supports it.
On the direct API you choose instead: payment_method.type selects the method (card by
default, apple_pay, google_pay…). The page-based flows are the only ones where the customer
picks.
Capture Modes
Auto Capture (default)
Funds are captured immediately after authorization.
Manual Capture
Use manual capture to authorize first, then capture when you're ready to fulfill the order.
# Capture the authorized payment
curl -X POST https://api.settleflow.io/v2/payments/pr_xxx/capture \
-H "X-Api-Key: your_api_key"Refunds
Refund a captured payment fully or partially:
curl -X POST https://api.settleflow.io/v2/payments/pr_xxx/refund \
-H "X-Api-Key: your_api_key" \
-H "Content-Type: application/json" \
-d '{ "amount": 500 }'Void
Cancel an authorized payment before capture:
curl -X POST https://api.settleflow.io/v2/payments/pr_xxx/void \
-H "X-Api-Key: your_api_key" \
-H "Content-Type: application/json" \
-d '{ "reason": "Customer cancelled" }'Payment Statuses
| Status | Description |
|---|---|
pending | Session created, awaiting card details |
authorized | Payment authorized, ready for capture |
captured | Funds captured |
refunded | Payment fully refunded |
voided | Authorization cancelled |
failed | Payment attempt failed |
rejected | Refused before reaching a provider |
rejected is not a decline. It means the payment was refused by our own
pre-authorization checks (risk rules) and was never submitted to a payment
provider, so no authorization was requested on the card and the transaction
carries no processing fee. It is returned by the API and included in your
transaction exports like any other transaction, but it is never settled and
never appears on a payout.