Payments Processing

Initiating credit transfers (Wires, ACH, RTP, FedNow) through ORCA. The workflow covers recipient identification, account validation, balance checks, payment initiation, status retrieval, and cancellation. ORCA's role is initiation only — the actual movement of funds across payment rails (RTP network, FedNow service, ACH operators, Fedwire) happens downstream at the Core or at a Payment Manager (e.g., PortX Payment Manager).

Business context

Payment orchestrators handling real-time payment networks (RTP, FedNow), batch ACH, and wire transfers need a normalized way to push payment instructions into many different financial institutions. Each Core (Fiserv, FIS, Jack Henry, etc.) speaks its own dialect and exposes payment posting differently; building a bespoke connector per Core multiplies the engineering effort.

ORCA exposes /credit-transfers as a single normalized REST resource based on ISO 20022 pain.001 semantics. The orchestrator submits a payment instruction; ORCA translates and forwards to the target Core or downstream Payment Manager, which then handles the rails-side processing (clearing, settlement, network messaging).

ORCA initiation boundary

The ORCA /credit-transfers endpoint is a payment initiation interface — it accepts the instruction, validates basic structure, and forwards it to the system that owns settlement. ORCA does not:

  • Send messages on the RTP network or to the FedNow service
  • Perform clearing or settlement
  • Manage the lifecycle states beyond what the downstream system reports back
  • Hold funds in any form (ORCA is stateless)

Use this page for what to send to ORCA. For rails-side behavior, consult the Payment Manager's documentation or the network specifications directly.

Scope

In-scope for this use case:

  • Recipient identificationPerson, Organization, and Account lookups by various identifiers (account number, phone number, email, tax ID, etc.)
  • Account validation — verifying that the recipient account exists, is Active, and can receive payments
  • Balance checks — pre-posting available-funds inspection
  • Credit transfer initiation — submitting payment instructions for all PaymentMethod values supported by the Core
  • Payment status retrieval — querying the lifecycle status (Received, AcceptedTechnicalValidation, AcceptedSettlementCompleted, Rejected, etc.)
  • Transaction history lookup — finding posted transactions on the recipient account
  • Cancellation — requesting cancellation of a previously initiated transfer (where supported by the rail)

Out-of-scope (handled elsewhere):

  • Rails network communication — RTP, FedNow, Fedwire, ACH network operations happen at the Core or downstream Payment Manager
  • Clearing and settlement — neither modeled nor performed by ORCA
  • Payment validation against scheme rules — RTP message format conformance, FedNow business rules, NACHA validation are handled downstream
  • Fraud screening, OFAC/AML scanning — performed by the Core or a dedicated fraud system, not by ORCA
  • Outbound payment origination from the FI's customer accounts — this use case covers receiving payments into the FI; outbound origination uses the same /credit-transfers endpoint but with different debtor/creditor framing and rail-specific concerns out of scope here

Architecture context

sequenceDiagram
    autonumber
    participant FT as Fintech<br/>(Payment Orchestrator)
    participant ORCA as ORCA API
    participant Core as FI Core /<br/>Payment Manager

    Note over FT: Inbound RTP/FedNow message arrives<br/>from the network at the orchestrator
    FT->>ORCA: GET /persons OR /accounts (lookup by identifier)
    ORCA->>Core: Recipient lookup
    Core-->>ORCA: Match
    ORCA-->>FT: 200 [Descriptors]

    FT->>ORCA: GET /accounts/{accountId} (account detail + status)
    ORCA->>Core: Account read
    Core-->>ORCA: Account data
    ORCA-->>FT: 200 {Account}

    opt Pre-posting balance check
        FT->>ORCA: GET /accounts/{accountId}/balances
        ORCA->>Core: Balance read
        Core-->>ORCA: Balances
        ORCA-->>FT: 200 [Balance[]]
    end

    Note over FT,Core: Step 4: Initiate the credit transfer
    FT->>ORCA: POST /credit-transfers (CreditTransferInitiation)
    ORCA->>Core: Forward payment instruction
    Note over Core: Core/Payment Manager handles:<br/>scheme validation, OFAC,<br/>rails messaging, settlement
    Core-->>ORCA: paymentId, initial status
    ORCA-->>FT: 202 {paymentId, status: "Received"}

    opt Status polling
        FT->>ORCA: GET /credit-transfers/{paymentId}
        ORCA->>Core: Status read
        Core-->>ORCA: Updated status
        ORCA-->>FT: 200 {CreditTransfer}
    end

    opt Cancellation (where supported by the rail)
        FT->>ORCA: POST /credit-transfers/{paymentId}/cancellation
        ORCA->>Core: Forward cancellation request
        Core-->>ORCA: Cancellation status
        ORCA-->>FT: 202 {status: "AcceptedCancellationRequest"}
    end

    opt Posted transaction lookup
        FT->>ORCA: GET /accounts/{accountId}/transactions
        ORCA->>Core: Transaction read
        Core-->>ORCA: Transactions
        ORCA-->>FT: 200 [Transaction[]]
    end

Endpoints used

Step Method Path Purpose
1 GET /persons Recipient lookup (personal)
1 GET /organizations Recipient lookup (commercial)
1 GET /accounts Account lookup by account number, identifier, etc.
1 GET /accounts/{accountId}/identifiers Retrieve alternate identifiers (phone, email aliases)
2 GET /persons/{personId} Recipient detail
2 GET /accounts/{accountId} Account detail + status
2 GET /accounts/{accountId}/owners Verify ownership
3 GET /accounts/{accountId}/balances Pre-posting balance check
4 POST /credit-transfers Initiate the credit transfer
5 GET /credit-transfers List credit transfers (with filters)
5 GET /credit-transfers/{paymentId} Retrieve a specific transfer
5 POST /credit-transfers/{paymentId}/cancellation Request cancellation
5 GET /accounts/{accountId}/transactions Posted transaction history

Common headers

Header Purpose
idempotencyId Critical for POST /credit-transfers. Network retries without idempotency cause duplicate payments.
servicerId Identifies the servicing institution.

Step 1 — Identify the recipient

When an inbound payment arrives at the orchestrator, the message carries identifiers — account number, routing number, phone, email, tax ID, or a token alias. Resolve those to an ORCA personId + accountId pair.

By account number

GET /accounts?accountNumber.eq=1234567891 HTTP/1.1
Host: api.portx.io
Authorization: Bearer <jwt>
servicerId: bank-001
[
  {
    "accountId": "acct-003-chk-1f2e3d4c",
    "accountNumber": "1234567891",
    "accountType": "Checking",
    "status": "Active",
    "routingNumbers": [
      { "number": "021000021", "type": "ABA" }
    ]
  }
]

By alternate identifier (RTP/FedNow alias)

For RTP and FedNow, recipients are often identified by a token — a phone number, email, or proxy ID maintained in a directory. The Core may store these aliases as Account.identifiers[] or Account.alternativeNames[].

GET /accounts?identifier.eq=%2B15125550100 HTTP/1.1

or

GET /accounts/{accountId}/identifiers HTTP/1.1

By person + person's accounts

GET /persons?phoneNumber.eq=%2B15125550100 HTTP/1.1

Then resolve the person's accounts:

GET /persons/{personId}/accounts HTTP/1.1

Step 2 — Retrieve account detail and verify status

Before posting, confirm the account is in a state that can receive funds.

GET /accounts/acct-003-chk-1f2e3d4c HTTP/1.1
{
  "accountId": "acct-003-chk-1f2e3d4c",
  "accountNumber": "1234567891",
  "accountType": "Checking",
  "ownershipType": "JointAccount",
  "status": "Active",
  "currency": "USD",
  "parties": [
    { "partyId": "person-7f3a8c92-4b1e-4d2f-9a0c-1b2c3d4e5f60", "partyAccountRole": "AccountOwner", "name": "Jane M Doe" }
  ]
}

The recipient account is good to receive a payment when status: "Active" and no blocking restrictions are present. Other relevant statuses for payments: Closed, Dormant, Restricted, Frozen — all should reject inbound credits.


Step 3 — Pre-posting balance check (optional)

For inbound payments to a deposit account, balance checks are usually unnecessary — credits don't fail on insufficient funds. The check is more relevant for outbound payments (debit-side), and for inbound payments that have a contingent return (e.g., a deposit that needs to immediately fund another transaction).

GET /accounts/acct-003-chk-1f2e3d4c/balances HTTP/1.1
[
  { "name": "AvailableBalance",  "amount": "2450.18", "currency": "USD", "creditDebitIndicator": "Credit" },
  { "name": "CurrentBalance",    "amount": "2450.18", "currency": "USD", "creditDebitIndicator": "Credit" },
  { "name": "AvailableOverdraft","amount": "500.00",  "currency": "USD" }
]

Step 4 — Initiate the credit transfer

POST /credit-transfers202 Accepted with CreditTransfer in the body.

Key request fields (CreditTransferInitiation)

Field Required Description
amount yes Decimal string (e.g., "100.00").
debtorAccountId yes The account being debited (the source of funds).
creditorAccountId conditional The account being credited. For inbound payments where the creditor is at the FI, this is the recipient's accountId.
paymentMethod yes The means of payment — see table below.
paymentType recommended OnUs, ACH, Wire, NotOnUs, LiquidityTransfer.
currency no Defaults to USD.
valueDate no Date the payment value is effective.
dueDate no Date the payment is due to be made.
purpose no Free-text description of why the payment is being made.
paymentProcessing recommended instructionPriority, serviceLevel, clearingChannel, localInstrument, categoryPurpose. This is where rail-specific framing lives.
chargeBearerType no Who pays fees: Debtor, Creditor, Shared, ServiceLevel.
creditor recommended Full PartyIdentification for the receiving party.
debtor recommended Full PartyIdentification for the sending party.
parties[] no Additional parties in the payment chain (intermediary banks, ultimate creditor/debtor).
remittanceInformation no Invoice number, document type, structured remittance data.
identifiers[] recommended Carry external identifiers (e.g., RTP messageId, FedNow UETR).

paymentMethod values

Value Use
CreditTransfer Generic credit transfer; pair with paymentType for rail.
ACHCredit ACH credit entry.
ACHDebit ACH debit entry (less common for "credit transfer" framing).
FedWire Fedwire transfer.
EFTCredit / EFT Electronic funds transfer.
Check, ECheck Check / electronic check.
Cash Cash deposit / withdrawal entry.
MoneyOrder, Coupon, LockBox, RemoteCapture Specialized payment forms.

Where does RTP and FedNow fit?

Neither RTP nor FedNow appears as a standalone paymentMethod enum value. They are conveyed through the combination:

  • paymentMethod: "CreditTransfer"
  • paymentType: "OnUs" (intra-bank) or appropriate variant
  • paymentProcessing.clearingChannel: "RTGS" or rail-specific value
  • paymentProcessing.localInstrument: "RTP" / "FedNow"
  • paymentProcessing.serviceLevel: "URGP" (urgent) or similar

Confirm with the integration team which localInstrument codes the target Core/Payment Manager expects.

ISO 20022 — debtor / creditor

In ISO 20022 payment messages, debtor is the party whose account is debited (paying), and creditor is the party whose account is credited (receiving). This holds regardless of who initiates the message — for an inbound RTP payment arriving at your FI, the debtor is the external customer at the originating bank, and the creditor is your FI's customer.

Inbound RTP payment example

POST /credit-transfers HTTP/1.1
Host: api.portx.io
Content-Type: application/json
idempotencyId: e8f9a0b1-c2d3-4e5f-6a7b-8c9d0e1f2a3b
servicerId: bank-001
{
  "amount": "150.00",
  "currency": "USD",
  "paymentMethod": "CreditTransfer",
  "paymentType": "NotOnUs",
  "debtorAccountId": "ext-acct-originating-bank-987654",
  "creditorAccountId": "acct-003-chk-1f2e3d4c",
  "paymentProcessing": {
    "instructionPriority": "High",
    "serviceLevel": "URGP",
    "clearingChannel": "RTGS",
    "localInstrument": "RTP",
    "categoryPurpose": "SUPP"
  },
  "purpose": "Reimbursement",
  "debtor": {
    "name": {
      "name": "Alex P Customer"
    },
    "account": {
      "accountNumber": "9988776655",
      "agent": {
        "bankIdentifier": "121000248",
        "name": "Wells Fargo Bank, NA"
      }
    }
  },
  "creditor": {
    "name": {
      "name": "Jane M Doe"
    }
  },
  "identifiers": [
    { "schemeName": "EndToEndId", "number": "RTP-2026-051900001234" },
    { "schemeName": "UETR",       "number": "e8f9a0b1-c2d3-4e5f-6a7b-8c9d0e1f2a3b" }
  ],
  "remittanceInformation": {
    "remittanceNumber": "INV-2026-04823",
    "documentType": "CommercialInvoice"
  }
}
{
  "paymentId": "pay-2a3b4c5d-6e7f-8a9b-0c1d-2e3f4a5b6c7d",
  "status": "Received",
  "amount": "150.00",
  "currency": "USD",
  "paymentMethod": "CreditTransfer",
  "paymentType": "NotOnUs",
  "debtorAccountId": "ext-acct-originating-bank-987654",
  "creditorAccountId": "acct-003-chk-1f2e3d4c",
  "date": "2026-05-19T14:42:08Z",
  "identifiers": [
    { "schemeName": "EndToEndId", "number": "RTP-2026-051900001234" }
  ]
}

FedNow payment example

Identical structure; differs in paymentProcessing.localInstrument:

{
  "amount": "75.50",
  "paymentMethod": "CreditTransfer",
  "paymentType": "NotOnUs",
  "debtorAccountId": "ext-acct-originating-bank-447712",
  "creditorAccountId": "acct-003-chk-1f2e3d4c",
  "paymentProcessing": {
    "instructionPriority": "High",
    "serviceLevel": "URGP",
    "localInstrument": "FedNow",
    "categoryPurpose": "CASH"
  },
  "purpose": "Personal transfer",
  "identifiers": [
    { "schemeName": "EndToEndId", "number": "FN-2026-051900447712" }
  ]
}

ACH credit example

{
  "amount": "1250.00",
  "paymentMethod": "ACHCredit",
  "paymentType": "ACH",
  "debtorAccountId": "ext-acct-payroll-employer-001",
  "creditorAccountId": "acct-003-chk-1f2e3d4c",
  "paymentProcessing": {
    "categoryPurpose": "SALA",
    "localInstrument": "PPD"
  },
  "purpose": "Payroll",
  "valueDate": "2026-05-22",
  "creditor": {
    "name": { "name": "Jane M Doe" }
  },
  "debtor": {
    "name": { "name": "Acme Industries LLC" },
    "agent": { "bankIdentifier": "021000089" }
  },
  "identifiers": [
    { "schemeName": "TraceNumber", "number": "021000089-1234567890" }
  ]
}

Step 5 — Status and history

Retrieve a specific payment

GET /credit-transfers/{paymentId}

{
  "paymentId": "pay-2a3b4c5d-6e7f-8a9b-0c1d-2e3f4a5b6c7d",
  "status": "AcceptedSettlementCompleted",
  "statusReason": "Settled",
  "amount": "150.00",
  "currency": "USD",
  "paymentMethod": "CreditTransfer",
  "creditorAccountId": "acct-003-chk-1f2e3d4c",
  "debtorAccountId": "ext-acct-originating-bank-987654",
  "settlement": {
    "postingType": "HardPosted",
    "time": "2026-05-19T14:42:11.481Z"
  },
  "date": "2026-05-19T14:42:08Z"
}

Payment status lifecycle

ISO 20022 pain.002 and pacs.002 define a rich set of status values. The most commonly seen for credit transfers:

Status Meaning
Received ORCA accepted the instruction; not yet validated by the Core.
AcceptedTechnicalValidation Schema and basic validation passed at the Core.
AcceptedCustomerProfile Customer-side validation (limits, profile rules) passed.
AcceptedSettlementInProcess Settlement initiated on the rail.
AcceptedSettlementCompleted Funds settled at the destination. Terminal success state.
Pending Awaiting downstream action.
Rejected Validation failure or rail-side rejection. statusReason carries why.
AcceptedCancellationRequest Cancellation request accepted (pending action).
RejectedCancellationRequest Cancellation rejected.

statusReason values (common)

AbortedClearingTimeout, AbortedSettlementTimeout, ErrorCreditorAgent, OfflineAgent, InvalidAccount, AccountClosed, InsufficientFunds, DuplicateMessage, FraudSuspected, BlockedByPolicy, ReturnedByBeneficiary.

List with filters

GET /credit-transfers?status.eq=Rejected&creationDate.gte=2026-05-19&creditorAccountId.eq=acct-003-chk-1f2e3d4c HTTP/1.1

Cancellation

POST /credit-transfers/{paymentId}/cancellation

{
  "cancellationReason": "Duplicate instruction sent by orchestrator at 14:42:09"
}

Cancellation is only meaningful for payments still in flight. RTP and FedNow are settled within seconds; once AcceptedSettlementCompleted, cancellation is not possible — recovery must use a return transaction or business resolution between counterparties.

Posted transaction history

GET /accounts/acct-003-chk-1f2e3d4c/transactions?paymentId.eq=pay-2a3b4c5d-6e7f-8a9b-0c1d-2e3f4a5b6c7d HTTP/1.1

Returns the posted ledger entry on the recipient account with full transaction metadata.


Error handling

Status When
400 Bad Request Schema validation failure: missing amount, debtorAccountId, or paymentMethod.
404 Not Found debtorAccountId or creditorAccountId references an unknown account.
409 Conflict Idempotency collision — same idempotencyId with different request body. Treat as a duplicate prevention success, not an error.
422 Unprocessable Entity Core or Payment Manager rejected the instruction on business grounds (account closed, daily limit exceeded, OFAC hit).
500 Internal Server Error Unexpected ORCA or Core failure.
502 Bad Gateway Core or Payment Manager unreachable.
503 Service Unavailable Payment Manager congestion; safe to retry with the same idempotencyId.

Edge cases and caveats

Idempotency is non-negotiable

Always send idempotencyId on POST /credit-transfers. Network retries without it create duplicate payments. The orchestrator should generate a UUID per intended payment, keep it associated with the source message (RTP/FedNow EndToEndId), and use it for every retry of that payment.

202 ≠ settled

POST /credit-transfers returns 202 Accepted — meaning the instruction is forwarded to the Core/Payment Manager. It does not mean the funds have settled or that the rails-side processing succeeded. Poll GET /credit-transfers/{paymentId} or subscribe to status webhooks (if configured) to track the lifecycle through to AcceptedSettlementCompleted.

ORCA does not perform OFAC, sanctions, or fraud screening

Compliance screening happens at the Core or in a dedicated fraud system. A Rejected status with statusReason: "BlockedByPolicy" or "FraudSuspected" indicates a downstream block, not an ORCA rule.

RTP/FedNow timing

Real-time rails complete in seconds. The full lifecycle (ReceivedAcceptedSettlementCompleted) may finish before the orchestrator polls for status. Consider this when designing the polling cadence — a 404 is unlikely, but a fully-terminal status on the first poll is common.

Cancellation is best-effort

Once a payment reaches AcceptedSettlementCompleted on an irrevocable rail (RTP, FedNow, Fedwire), it cannot be cancelled. The orchestrator must initiate a separate return or refund transaction.

Currency

The ORCA spec supports multi-currency via currency, but RTP, FedNow, ACH, and Fedwire are USD-only domestic rails. Cross-border payments are out of scope for this use case.

Posting type — memo vs hard

settlement.postingType: "MemoPosted" indicates a provisional posting (visible in balance, not yet hard-posted). "HardPosted" is the final ledger commit. Cores differ in when they transition; consult the Core's documentation for posting cycle behavior.

Related building blocks

  • Account Opening — Recipient accounts must exist before they can receive a payment. See Account Opening.
  • Internal Transfers — For intra-bank money movement (account ↔ account at the same FI), use /internal-transfers instead. See Customer Service.
  • PortX Payment Manager — Downstream component that handles rails messaging and settlement. Refer to its documentation for rails-side behavior.