FloPayFloPay
API ReferenceREST API

Payments and authorisations

Payment reporting fields, manual-capture states, capture and cancellation operations, authentication, errors, and retry rules.

Payments and authorisations

The payments API exposes one-time card authorisations as a provider-neutral lifecycle. If captureMethod is omitted, or set to automatic, immediate capture remains the default. Manual capture is opt-in and supports one later capture for the full amount.

Financial event fields

Payment resources classify purchases, refunds, and chargebacks explicitly. The following fields are additive; existing response fields are unchanged.

FieldTypeMeaning
typepurchase / refund / chargebackFinancial event classification. Use this instead of inferring a chargeback from status or provider-specific metadata.
financialEffectiveAtISO 8601 timestamp or nullThe authoritative provider money-movement timestamp, when available.
gatewayChargeIdstring or nullThe provider charge id that links a refund or chargeback movement to the original purchase.

For example, a chargeback withdrawal can appear as:

{
  "id": "3c54b6ac-7ad5-4e56-9c2c-5a80c2ef40d0",
  "amount": 49.99,
  "currency": "GBP",
  "type": "chargeback",
  "financialEffectiveAt": "2026-08-14T12:05:43.000Z",
  "gatewayChargeId": "ch_3Qx9Example"
}

Chargeback amounts are signed from Flo's reporting perspective: a positive amount is money withdrawn, while a negative amount is money reinstated after a dispute win. To reconcile Stripe, group Stripe movements by the provider dispute identity retained in metadata and sum their signed amounts. Do not count each lifecycle notification as a separate chargeback.

Chargeback rows never participate in refund aggregation. This reporting contract applies prospectively and does not reclassify or replay historical transaction rows.

Checkout opt-in

POST /v1/checkouts/sessions accepts:

{
  "clientId": "18bff186-284c-483f-acee-e712f21d2b8d",
  "captureMethod": "manual",
  "currency": "GBP",
  "products": [{ "code": "order_123", "quantity": 1 }],
  "accountData": {
    "userId": "customer_123",
    "email": "customer@example.com"
  },
  "successUrl": "https://merchant.example/order/accepted",
  "cancelUrl": "https://merchant.example/checkout"
}
FieldTypeRequiredMeaning
captureMethodautomatic | manualNoautomatic is the default. manual requests an authorisation hold.

Manual capture is eligible only for one-time card carts. Subscriptions, PayPal, other alternative payment methods, partial capture, incremental authorisation, and multiple capture are unsupported.

After cardholder authentication, GET /v1/checkouts/sessions/{sessionId}/status can return:

{
  "data": {
    "uuid": "fd4475e4-dc19-4439-b830-c9c8f67a35e7",
    "status": "authorized",
    "paymentId": "3c54b6ac-7ad5-4e56-9c2c-5a80c2ef40d0",
    "authorizationExpiresAt": "2026-08-11T14:30:00.000Z",
    "latestTransactionAttempt": {
      "result": "AUTHORIZED"
    }
  }
}

Authenticate the status read with the session's x-checkout-session-token. Save paymentId; capture and cancellation accept the FloPay payment UUID, not a provider intent id.

Payment states

Payment.status is the canonical TransactionStateEnum value:

StatusMeaningMoney collected?
pendingCreated but not yet submitted to a terminal provider outcome.No
authorizedFunds are held and capturable before authorizationExpiresAt.No
processingProvider processing is in progress.Not yet confirmed
succeededCaptured and paid. Immediate-capture payments also finish here.Yes
failedDeclined, authentication-failed, or otherwise terminally failed.No
refundedThe captured amount has been fully refunded.Previously collected
partially_refundedPart of the captured amount has been refunded.Partially retained
refund_failedA refund attempt failed; inspect the payment and refund operation before retrying.Unchanged
voidedAn uncaptured hold was cancelled or expired. Inspect authorizationVoidReason.No
unknownFloPay cannot classify the provider state yet. Re-read before acting.Do not assume

There is no captured, declined, cancelled, or expired payment status. A captured payment is succeeded; a declined authorisation is failed; a cancelled authorisation is voided with reason merchant_requested; and an expired authorisation is voided with reason expired. Provider cancellation can use provider_canceled.

Never treat authorized as paid. Fulfil an item order only after capture returns succeeded and your idempotent webhook handler processes item.purchased.

Capture the full authorisation

PUT /v1/payments/{paymentId}/capture
Authorization: Basic {base64(clientUuid:apiToken)}
Idempotency-Key: order_123-full-capture
Content-Type: application/json

{}

The optional JSON body is included in the idempotent request identity. A 200 OK response returns the payment resource. On success its status is succeeded.

Cancel an authorisation

PUT /v1/payments/{paymentId}/cancel
Authorization: Basic {base64(clientUuid:apiToken)}
Idempotency-Key: order_123-cancel
Content-Type: application/json

{}

A successful cancellation returns 200 OK with status: 'voided' and authorizationVoidReason: 'merchant_requested'. It releases the hold without collecting funds.

Authentication and permissions

Capture and cancellation are trusted-server operations. They accept Client Basic authentication with the client identifier (client.uuid) as the username and an active user-owned API token as the password. OAuth bearer callers must have a current merchant owner or admin membership. A member or revoked membership receives 403 Forbidden.

The payment is scoped to the authenticated merchant before FloPay resolves provider details. A missing payment and another merchant's payment both return the same 404 Not Found response.

Never expose a user-owned API token or OAuth access token to browser code. The FloPay SDK deliberately has no capture or cancellation method.

Idempotency and retries

Idempotency-Key is mandatory and must be nonblank. Use one stable key per logical operation:

  • retry the same operation with the same key and the same request body after a timeout, lost response, or 5xx;
  • never reuse that key for a different payment, operation, or body;
  • the same key with a different body returns 409 Conflict and preserves the original operation;
  • a durable replay returns the original outcome and never submits a second provider capture.

Capture failure returns 502 Bad Gateway, leaves the authorisation inspectable rather than claiming payment, and emits payment.capture_failed. Re-read the payment before deciding whether another operation is appropriate.

Errors

HTTP statusWhen it is returnedAction
400Invalid payment UUID, or missing/blank Idempotency-Key.Correct the request; do not retry unchanged.
403OAuth caller is not a current owner or admin.Use an authorised server identity.
404Payment is missing or outside the merchant scope.Treat both cases identically; do not probe provider data.
409Payment is not actively authorised, the hold expired, another operation is active, or the key conflicts with another request.Re-read the payment and reconcile; do not generate a new key for an uncertain request.
502The gateway could not capture or cancel.Keep the order unfulfilled, re-read state, and use the same key for a safe transport retry.

Events

EventMeaning
payment.authorizedA capturable hold is active. Not a fulfilment signal.
payment.capture_failedA capture attempt failed and no paid outcome was produced.
payment.authorization_voidedThe merchant released an uncaptured hold.
payment.authorization_expiredThe provider expired an uncaptured hold.
item.purchasedThe capture completed through the existing purchase path; canonical fulfilment event for this item-only flow.

See Pre-authorisation and capture for the end-to-end task and Webhook events for payloads.

On this page