Corgi BankDocumentation
OpenAPI

Incoming payments and returns

The bank answers a payment another participant sends in the same exchange. This page covers that answer, returns in both directions, and the states and events of a Realtime Transfer.

How a payment arrives

The rail's operator delivers every message to POST /rails/realtime/inbound, a route only the rail's own identity may call. For a pacs.008 the bank records a Realtime Transfer with direction inbound and answers with a pacs.002:

AnswerStatusWhen
ACTCreceivedThe creditor account is open and the debtor's name screens clear. The account is credited before the answer goes back.
ACWPheld_for_reviewThe debtor's name did not screen clear. The funds settle and wait on the transit account, GL 2320.
RJCTrejectedRejected with a reason code: AG01 when the creditor agent is not this bank, AM11 when the currency is not USD, AC03 when no account has that number, AC04 when the account is closed, AC06 when it is in any other state that is not open.

A message id seen before gets the answer first given, and nothing posts twice. If the ledger cannot be reached the bank sends no status report, and the operator delivers again. A payment whose end-to-end id names one of the bank's open requests for payment marks that request paid.

Decide a held payment

POST /transfers/realtime/{id}/review takes decision and actor. An Idempotency-Key is optional and replays the recorded decision. On an inbound payment:

  • approve moves the funds from the transit account to the customer's account, sets received and tells the sender ACCC.
  • reject tells the sender RJCT with RR04, sets rejected and sends the funds back as a return. Once that settles the payment is returned.
  • block tells the sender BLCK and leaves the funds on the transit account as blocked. A blocked payment cannot be reviewed again.

An outbound payment held for review uses the same route with approve or reject.

Return a payment the bank received

POST /transfers/realtime/{id}/returns is an operator action. It takes reason_code (an ISO 20022 return reason such as AC04, DUPL or FRAD), operator, and optionally reason and an amount below the original. The payment must be received, held_for_review or rejected, or the answer is payments.payment_not_returnable.

On FedNow the return is a pacs.004. On RTP it is a new credit transfer whose remittance reads RETURN <message id> <reason code> <reason>. The return is a Realtime Transfer of its own, with kind return and original_id. The funds come from the customer's account under a hold when the payment was posted, and from the transit account when it was not. While a return of a payment is in flight or settled, another is refused. When the service settles the return, the original becomes returned.

Return requests

POST /transfers/realtime/{id}/return-requests sends a camt.056 about a payment the bank sent. The payment must be accepted, accepted_without_posting or posted, and reason_code is one of DUPL, FRAD, TECH, UPAY, CUST, AGNT, AM09, CURR or CUTA. The Realtime Return Request goes from requested to acknowledged, then by the receiver's camt.029 to accepted (IPAY or PECR), rejected (RJCR) or pending (PDCR), and to returned when the money arrives, with return_payment_id.

A camt.056 from another participant is recorded as received and decided with POST /realtime-return-requests/{id}/respond, as for a wire: honour sends the camt.029 and the return, and ends honoured; refuse sends RJCR and ends refused.

When a payment the bank sent comes back, the account that paid is credited, the original becomes returned with its return_reason_code, and the bank's open return requests on it close. The returning party is screened first; a hit parks the funds on the transit account as held_for_review.

States and events

StatusDirectionMeaning
pendingoutboundRecorded with its funds on hold.
held_for_reviewbothWaiting for a person: screening, the fraud rules, or an inbound payment accepted without posting.
sendingoutboundClaimed; the message is on its way. One claim wins, so one message leaves.
sentoutboundNo answer from the service. The hold stays until a status request settles or fails the payment.
acceptedoutboundSettled and debited.
accepted_without_postingoutboundSettled and debited; the receiver has not posted yet.
postedoutboundThe receiver confirmed the posting.
rejected_by_railoutboundThe receiver or the service rejected it. The hold is released.
rejectedbothOutbound: refused at review, never sent, or rejected by the receiver after ACWP. Inbound: the bank answered RJCT.
blockedbothThe receiver blocked the funds, or the bank did at review.
receivedinboundCredited to the account, or for the bank's own funds to a GL account.
returnedbothThe payment went back.

Each status is an event type, such as payments.instant.received, with the transfer as its data. Listen for payments.instant.received to see money arrive, payments.instant.accepted and payments.instant.rejected_by_rail for a payment you sent, payments.instant.held_for_review for the review queue, and payments.instant.returned on either side. Return requests publish payments.instant_return_request.*.

Testing

POST /simulate/transfers/realtime/receive plays another participant paying one of the bank's account numbers, POST /simulate/transfers/realtime/return plays the receiver returning a payment the bank sent, and POST /simulate/transfers/realtime/return-request plays the sender asking for one back.

to move to open esc to close