Inbound Wires
Decide and post wires received from the Fed, and return them
Overview
When you process a file holding a credit transfer (pacs.008, or pacs.009), Twisp decides which account to credit and posts the wire as a WIRE_INBOUND workflow execution. The execution id is the message id of the file's message.
decision RETURN
(received) ─────────> SETTLE ─────────────────> RETURN
│ ▲ ▲
│ decision │ SETTLE │ RETURN
└──────────> PENDING ───────────────────────┘
A Fedwire credit is final when it arrives, so a wire settles at once. There is no settlement date to wait for.
Decisioning
The configuration's decisioning mode decides each wire:
| Mode | Decision |
|---|---|
WEBHOOK | Your endpoint answers the create webhook |
PENDING | The wire is credited to the pending account as PENDING |
ACCOUNT_LOOKUP | Twisp evaluates the src to an externalId and settles the wire to that account. When no account has the externalId, the source fails, or the account is one of the configuration's accounts, the wire is returned with AC03. |
Every mode has the webhook contract: it is asked with the webhook request below and answers with a webhook response.
Webhook Request
Twisp POSTs to the configured endpoint, signed with x-twisp-signature like the ACH webhooks:
{
"workflowTask": "CREATE",
"workflowName": "WIRE.INBOUND",
"executionId": "0b9e44a2-6d0c-5b3e-9f1a-2c3d4e5f6a7b",
"configurationId": "5d1c6a0e-8b7f-4e2a-9c3d-2e1f0a9b8c7d",
"fileId": "3f1e2d3c-4b5a-6978-8a9b-0c1d2e3f4a5b",
"messageId": "0b9e44a2-6d0c-5b3e-9f1a-2c3d4e5f6a7b",
"messageElement": "FedwireFundsCustomerCreditTransfer",
"creditTransfer": {
"msgId": "20261009B1QDRCQR000001",
"creationTime": "2026-10-09T09:00:00-04:00",
"settlementDate": "2026-10-09T00:00:00Z",
"uetr": "8a562c67-ca16-48ba-b074-65581be6f011",
"endToEndId": "Scenario01EtoEId001",
"amountCents": 51000074,
"currency": "USD",
"localInstrument": "CTRC",
"debtor": {
"name": "Corporation A",
"account": "92315266453",
"address": { "streetName": "Avenue of the Fountains", "townName": "Phoenix", "country": "US" }
},
"creditor": {
"name": "Corporation B",
"account": "567876543",
"address": { "streetName": "Desert View Street", "townName": "Bisbee", "country": "US" }
},
"debtorAgent": { "routingNumber": "011104238" },
"creditorAgent": { "routingNumber": "021040078" },
"instructingAgent": { "routingNumber": "011104238" },
"instructedAgent": { "routingNumber": "021040078" },
"remittance": ["Payment for invoice 4562"]
}
}
creditTransfer is the normalized message. Its fields:
| Field | Description |
|---|---|
msgId | The sender's IMAD |
creationTime, settlementDate | Message creation time and interbank settlement date |
uetr, endToEndId, instrId | Payment identifiers |
amountCents, currency | The amount in cents, and USD |
localInstrument | Such as CTRC (customer transfer) or BTRS (bank transfer) |
debtor, creditor | name, account (accountIBAN is true for an IBAN), address; for a pacs.009, routingNumber or bic |
debtorAgent, creditorAgent, instructingAgent, instructedAgent | Banks: routingNumber, bic, name, address |
intermediaryAgents | Banks between the instructed agent and the creditor agent, in order |
remittance | Unstructured remittance lines |
Fields with empty values are omitted.
Webhook Response
{
"action": "SETTLE",
"accountId": "6b879478-27e0-4fde-9038-ef81b028bb51",
"metadata": { "note": "matched by account number" }
}
| Field | Description |
|---|---|
action | SETTLE, PENDING, RETURN or RETRY |
accountId | The account to credit, for SETTLE and PENDING. It cannot be the configuration's settlement, suspense, exception or pending account. |
reasonCode, reasonInfo | For RETURN: an ISO return reason code, such as AC03 or AC04, and free text. The code defaults to NARR. |
metadata, entryMetadata | Metadata for the transaction and the account entry |
RETRY, or a webhook that fails, retries the decision.
Account Lookup
An ACCOUNT_LOOKUP source reads the request's creditTransfer as creditTransfer:
Your externalId is | src |
|---|---|
| The plain account number | creditTransfer.creditor.account |
| A string format | 'dda:' + creditTransfer.creditor.account |
| A v5 UUID of routing and account number | uuid.NewSHA1(uuid('<your namespace>'), bytes(creditTransfer.creditorAgent.routingNumber + creditTransfer.creditor.account)) |
A settled wire records the externalId it found as metadata.accountLookup.externalId.
Posting
| Decision | Ledger |
|---|---|
SETTLE | Posts SYS_WIRE_INBOUND_SETTLE_CR to the account |
PENDING | Posts SYS_WIRE_INBOUND_PENDING_CR to the account's pending layer |
RETURN | Credits the suspense account (SYS_WIRE_INBOUND_SETTLE_CR), then returns the wire (SYS_WIRE_INBOUND_RETURN_DR) |
If the credit cannot post, for example because a velocity control on the account refuses it or the account is locked, the wire is credited to suspense and returned with NARR and the error code as its reason.
The message's detail records the outcome, such as settle or returned AC03 ACCOUNT NOT FOUND.
Resolving PENDING Wires
Settle or return a pending wire with Mutation.workflow.execute() and code WIRE_INBOUND. The execution id is the message id.
mutation SettlePendingWire {
workflow {
execute(
input: {
executionId: "0b9e44a2-6d0c-5b3e-9f1a-2c3d4e5f6a7b"
code: "WIRE_INBOUND"
task: "SETTLE"
params: { accountId: "6b879478-27e0-4fde-9038-ef81b028bb51" }
}
) {
executionId
output {
state
}
}
}
}
| Task | From | Parameters | Ledger |
|---|---|---|---|
SETTLE | PENDING | accountId (settles to another account), effective, metadata, entryMetadata | Voids the pending credit (SYS_WIRE_INBOUND_PENDING_VOID_DR), posts SYS_WIRE_INBOUND_SETTLE_CR |
RETURN | PENDING | reasonCode, reasonInfo | Voids the pending credit |
RETURN | SETTLE | reasonCode, reasonInfo | Posts SYS_WIRE_INBOUND_RETURN_DR to the account the wire settled to |
Returns
Every RETURN queues the wire. The next generateFile writes a pacs.004 that returns the full amount to the original sender, with the return's reasonCode and reasonInfo. Without a code, the pacs.004 uses NARR.
Only a wire received as a credit transfer (pacs.008 or pacs.009) can be returned, because its pacs.004 is built from that message. RETURN fails with BAD_REQUEST for any other wire, such as an unmatched return credited to the exception account, and changes nothing.
Duplicates and Unmatched Returns
- A credit transfer whose UETR an earlier inbound wire already has is recorded as
IGNOREDand does not post. - A pacs.004 that matches none of your outbound wires is posted as an inbound wire to the configuration's exception account. Its message
detailreadsunmatched return credited to the exception account. It has no credit transfer to send back, soRETURNrefuses it withBAD_REQUEST. Resolve the funds with your own transactions.