Payment Lifecycle
A payment moves through a fixed set of statuses, whichever processor ends up handling it. This page describes each status, what moves a payment between them, and which operations you can call in each status.
Payment Statuses
The status field on every payment response is one of the following values:
Status | Meaning |
|---|---|
requires_confirmation | The payment was created with confirm: false and has not been sent to a processor yet. Call confirm to authorize it. |
requires_action | The customer must complete 3DS authentication. The response includes nextAction with the token to pass to the Forter SDK. After the challenge completes, call confirm. |
processing | The processor has not returned a final result yet, for example an asynchronous authorization or a capture or cancellation that is still pending. Wait for a webhook or retrieve the payment. |
requires_capture | The payment is authorized and the funds are on hold (captureMethod: manual). Capture it before authorizationExpiresAt. |
succeeded | Funds were captured. Refunds don't change this status; track refunded money with refundedAmount. The one exception is a full refund of an unsettled sale, which voids it and moves the payment to canceled. |
failed | Authorization was declined or failed, or the capture failed. See Declines and Retries. |
canceled | The payment was canceled: by you, by Forter because of a fraud decline or a failed 3DS authentication, or because an unsettled sale was voided by a full refund. This status is final. |
New statuses may be added over time. Handle unknown values gracefully, for example by treating them like processing and retrieving the payment later.
Status Flow
flowchart TD
Create["Create payment"] -->|"confirm: false"| RC["requires_confirmation"]
Create -->|"3DS required"| RA["requires_action"]
Create -->|"confirm: true"| Auth{"Authorization"}
Create -->|"fraud decline / failed 3DS"| C["canceled"]
RC -->|"confirm"| Auth
RA -->|"3DS completed, confirm"| Auth
Auth -->|"pending at processor"| P["processing"]
P --> Auth
Auth -->|"captureMethod: manual"| RCap["requires_capture"]
Auth -->|"captureMethod: automatic"| S["succeeded"]
Auth -->|"declined"| F["failed"]
F -->|"confirm (retry)"| Auth
RCap -->|"capture"| S
RCap -->|"cancel"| C
RC -->|"cancel"| C
RA -->|"cancel"| CAvailable Operations by Status
Operation | Allowed when status is |
|---|---|
POST /api/payments/{id}/confirm | requires_confirmation, requires_action, failed (retries a declined authorization) |
POST /api/payments/{id}/capture | requires_capture |
POST /api/payments/{id}/cancel | requires_confirmation, requires_action, requires_capture |
POST /api/payments/{id}/reauthorize | requires_capture |
POST /api/payments/{id}/adjust-authorization | requires_capture, with nothing captured yet |
POST /api/payments/{id}/refunds | Any payment with captured funds that have not been fully refunded |
Calling an operation in a status that doesn't allow it returns an error and leaves the payment unchanged. See Errors.
Creating and Confirming
POST /api/payments creates the payment and runs the pre-authorization steps for your integration type, such as fraud decisioning, 3DS recommendation and routing.
- With confirm: true, Forter authorizes the payment in the same request.
- With confirm: false (the default), the payment is created in requires_confirmation and no processor is contacted until you call POST /api/payments/{id}/confirm.
If Forter requires 3DS, the create response has status requires_action and a nextAction object:
{
"status": "requires_action",
"nextAction": {
"type": "use_sdk",
"useSdk": {
"token": "<managed order token>"
}
}
}Pass nextAction.useSdk.token to the Forter 3DS SDK on your front end. When the challenge completes, call confirm with no body. Forter reads the authentication result and authorizes the payment, or cancels it if authentication failed.
Capture
captureMethod is set when you create the payment:
- automatic (default): Forter captures the full amount right after a successful authorization. The payment goes straight to succeeded.
- manual: the payment stops at requires_capture and holds the funds until you capture or cancel it.
POST /api/payments/{id}/capture accepts an optional amount:
{
"amount": 1000
}- Omit amount to capture everything that is still authorized.
- Send a smaller amount for a partial capture. You can't capture more than the authorized amount.
- Some processors support multiple partial captures against one authorization. With those processors, the payment stays in requires_capture after a partial capture, and you can capture again until the authorization is used up. With the others, the first capture is final and any uncaptured remainder is released.
Each successful capture appears as an entry in the payment's charges array. Pass a charge id as chargeId when you want to refund a specific capture.
Cancel
POST /api/payments/{id}/cancel releases an authorization that has not been captured. Both fields are optional:
{
"reason": "requested_by_customer",
"amount": 500
}- reason: one of duplicate, fraudulent, requested_by_customer, requested_by_merchant, abandoned.
- amount: releases only part of the hold (partial cancel). The remainder stays capturable. This is only available on processors that support partial authorization reversal.
If part of the payment was already captured, canceling releases the remaining hold and the payment moves to succeeded, because captured funds remain.
Authorization Expiry and Re-authorization
Card authorizations expire after a period that depends on the card network and the processor. When the processor reports it, the payment includes authorizationExpiresAt, which is the deadline for capturing the hold.
If you need more time, or a different amount, call POST /api/payments/{id}/reauthorize while the payment is in requires_capture:
- No body: renews the authorization for its current amount.
- With amount: moves the authorization to the new amount. After a partial capture, amount is what the remaining authorization should hold.
{
"amount": 12000,
"strategy": "adjust_first"
}strategy requires amount and controls how the new amount is reached:
Strategy | Behavior |
|---|---|
adjust_first (default) | Adjusts the existing authorization in place where the processor supports it, and otherwise creates a new authorization. |
adjust_only | Only adjusts in place. If the processor refuses, the request fails and the current authorization is kept. |
new_authorization | Always creates a new authorization, even for an amount that is already held. |
Re-authorization and authorization adjustment are only available on some processors. If the payment's processor doesn't support them, the request is rejected and the current authorization is left unchanged.
Adjust Authorization
POST /api/payments/{id}/adjust-authorization changes the amount on a live, uncaptured authorization without creating a new one. Use it, for example, when the order total changes before shipping. amount is the new total to hold:
{
"amount": 15000
}The payment ID, processor transaction and expiry date stay the same. You can't adjust a payment that is partially captured or whose authorization has expired. For those cases, use reauthorize with an amount.
Refunds
Refunds return captured funds to the customer.
Endpoint: POST /api/payments/{id}/refunds
{
"amount": 500,
"reason": "requested_by_customer"
}- amount (optional): omit it to refund everything that remains on the capture.
- reason (optional): one of duplicate, fraudulent, requested_by_customer, other.
- chargeId (optional): the capture to refund. If you omit it, Forter uses the most recent capture that has enough refundable balance.
You can issue several partial refunds against the same capture, up to its captured amount.
Settlement-aware refunds. If a full refund is requested before the processor has settled the capture, Forter voids the sale instead, so you don't have to track settlement yourself. The refund is returned with status voided. A partial refund before settlement is only possible on processors that support partial reversal. Otherwise you'll receive an error, and you can retry after the capture settles or issue a full refund.
Refund Statuses
Status | Meaning |
|---|---|
pending | The processor accepted the refund but hasn't completed it. Most processors report refunds asynchronously, so expect this status in the create response. |
succeeded | The refund completed. |
failed | The processor rejected the refund. |
voided | The capture had not settled, so the sale was voided instead of refunded. The customer is never charged. |
Retrieve refunds with GET /api/refunds/{id}, or list the refunds for a payment with GET /api/refunds?paymentId={paymentId}. The list is ordered newest first and accepts createdAfter, createdBefore (ISO 8601) and limit (1–100, default 10).
Amount Fields on a Payment
Field | Meaning |
|---|---|
amount | The payment total. Changes when you adjust or re-authorize with a new amount. |
authorizedAmount | The amount still on hold and available to capture. 0 once the authorization is fully captured or released. |
capturedAmount | The total of successful captures. |
refundedAmount | The total of succeeded refunds. Pending refunds are not included. |
All amounts are integers in the currency's minor unit. See Amounts and Currencies.
The matching timestamps are createdAt, authorizedAt, capturedAt and refundedAt. Fields that don't apply yet are omitted from the response rather than returned as null.