Overview

Every payment in OpenFX follows a defined lifecycle from creation to a terminal state. The lifecycle is the same whether the payment was created via the unified POST /payments endpoint or a rail-specific endpoint. Understanding these states is critical for building reliable payment integrations.

State Machine

Status Definitions

Provider status mapping

Payment statuses are normalized from provider-native values. The Platform API abstracts provider-specific status semantics into a consistent lifecycle:
Provider StatusOpenFX Payment StatusNotes
PENDINGprocessingPayment submitted to the rail, awaiting settlement
SETTLEDcompletedFunds delivered to the counterparty
FAILEDfailedPayment could not be processed
RETURNEDreturnedFunds returned by the receiving institution
This mapping ensures a consistent payment lifecycle regardless of the underlying banking provider. If providers change underneath (new provider, new capabilities), the status semantics remain stable for API consumers.

Active states

These statuses indicate the payment is still in progress and may transition further.
StatusDescriptionWhat to do
createdPayment has been accepted and is being prepared for processing. Compliance screening may be in progress.Wait for payment.processing webhook.
processingPayment is actively being processed on the payment rail. Funds have been debited from the source account.Wait for payment.completed or payment.failed webhook.
in_reviewPayment is undergoing manual review (compliance or operations). This is a temporary hold — no action is needed from you.Wait for the review to complete. The payment will resume processing or transition to completed or failed.

Terminal states

These statuses are final. The payment will not transition again (except completed which can lead to returned or reversed).
StatusDescriptionFinancial impact
completedPayment was successfully delivered to the counterparty.Funds have left your account and arrived at the destination. This is the happy path.
failedPayment could not be completed.Funds that were held are released back to the source account. Check failureReason for details.
returnedPayment was delivered but subsequently returned by the receiving institution (e.g., ACH return codes R01-R51).Returned funds are credited back to the source account.
reversedPayment was reversed after completion (e.g., due to fraud or error).Reversed funds are credited back to the source account.
The completed status means the payment was delivered but it is not necessarily a terminal state in all cases. A completed payment can still transition to returned or reversed if a post-delivery event occurs. Build your integration to handle these transitions even after a payment reaches completed.

Cancellation state

The cancellationState field is orthogonal to payment status. It tells you whether a payment can be canceled at its current point in the lifecycle, regardless of its status.
Cancellation StateMeaning
cancelableThe payment can be canceled via POST /payments/{paymentId}/cancel
not_cancelableThe payment has progressed past the point where cancellation is possible
A payment in created status is typically cancelable. Once it reaches processing, it becomes not_cancelable because funds have been submitted to the payment rail.

Webhook Events

Subscribe to these webhook events to react to payment status changes in real time.
EventTriggered whenPayment status
payment.createdPayment is accepted and createdcreated
payment.processingPayment has entered active processingprocessing
payment.in_reviewPayment is under manual reviewin_review
payment.completedPayment was successfully deliveredcompleted
payment.failedPayment could not be completedfailed
payment.returnedDelivered payment was returnedreturned
payment.reversedDelivered payment was reversedreversed
At a minimum, subscribe to payment.completed, payment.failed, and payment.returned. These three events cover the most common integration scenarios.

Lifecycle Timestamps

Every payment includes timestamps for key lifecycle events. These are null until the corresponding transition occurs.
FieldSet when
createdAtPayment is created (always present)
submittedAtPayment enters processing
completedAtPayment reaches completed
failedAtPayment reaches failed
returnedAtPayment is returned
reversedAtPayment is reversed

Failure Details

When a payment fails, the failure object provides structured information about what went wrong:
{
  "failure": {
    "code": "insufficient_funds",
    "message": "Source account has insufficient balance for this payment.",
    "railCode": null,
    "railMessage": null,
    "retryable": true
  }
}
FieldDescription
codeMachine-readable failure code: insufficient_funds, account_closed, invalid_account, compliance_rejected, rail_rejected, provider_error, timeout, unknown
messageHuman-readable explanation
railCodeRaw error code from the payment rail (e.g., ACH return code). Null if failure occurred before rail submission.
railMessageRaw error message from the payment rail
retryableWhether the payment can be retried with the same parameters

Return Details

When a completed payment is returned, the returnInfo object explains the return:
{
  "returnInfo": {
    "code": "R01",
    "reason": "Insufficient funds",
    "returnedBy": "Receiving Bank",
    "originalRail": "ach"
  }
}
ACH return window: ACH returns can arrive up to 2 business days after settlement for standard returns and up to 60 calendar days for unauthorized transaction disputes (R10, R29). Build your integration to handle returns arriving long after a payment reaches completed status.

Tracking Identifiers

Once a payment enters processing, OpenFX populates trackingIdentifiers with rail-native reference numbers for end-to-end traceability.
FieldRail(s)Description
uetrSWIFTUniversal End-to-End Transaction Reference (UUID format)
traceNumberACHTrace number assigned by the originating bank
imadFedwireInput Message Accountability Data
omadFedwireOutput Message Accountability Data
txHashCryptoBlockchain transaction hash
These identifiers are null until populated by the rail and are only present for the relevant rail type.
1. Create payment (POST /payments)
   |
2. Subscribe to webhooks:
   |  payment.completed
   |  payment.failed
   |  payment.returned
   |
3. On payment.completed:
   |  Record success, update your system
   |
4. On payment.failed:
   |  Record failure, notify stakeholders
   |  Check failureReason for retry guidance
   |
5. On payment.returned:
   |  Evaluate return reason
   |  Take appropriate action

API Reference