# Outbound Wires

Send wires with the WIRE_OUTBOUND workflow and settle them on the Fed's reply

## Overview

An outbound wire is a `WIRE_OUTBOUND` workflow execution. You create it, Twisp generates its pacs.008, and the Fed's reply settles or rejects it.

```
          generateFile         pacs.002 ACSC          pacs.004
CREATE ───────────────> SUBMIT ─────────────> SETTLE ─────────> RETURN
  │                       │
  │ CANCEL                │ pacs.002 RJCT / admi.002
  ▼                       ▼
CANCEL                  REJECT  (also from CREATE)
```

The funds are held in the customer account's pending layer from `CREATE` until the wire settles or is released.

## Create a Wire

Execute `CREATE` with [`Mutation.workflow.execute()`](https://www.twisp.com/docs/reference/graphql/mutations.md#workflow.execute) and code `WIRE_OUTBOUND`:

```graphql
mutation SendWire {
  workflow {
    execute(
      input: {
        executionId: "7c1d4e2a-0f3b-4c5d-8e9f-1a2b3c4d5e6f"
        code: "WIRE_OUTBOUND"
        task: "CREATE"
        params: {
          configId: "5d1c6a0e-8b7f-4e2a-9c3d-2e1f0a9b8c7d"
          accountId: "6b879478-27e0-4fde-9038-ef81b028bb51"
          amount: "25000.00"
          debtorName: "Jane Debtor"
          debtorAccount: "123456789"
          debtorAddress: "{\"streetName\":\"Main St\",\"buildingNumber\":\"1\",\"townName\":\"Springfield\",\"countrySubDivision\":\"IL\",\"postCode\":\"62701\",\"country\":\"US\"}"
          creditorName: "John Creditor"
          creditorAccount: "987654321"
          creditorRoutingNumber: "021000021"
          remittance: "Invoice 42"
        }
      }
    ) {
      executionId
      output {
        state
      }
    }
  }
}
```

### CREATE Parameters

| Parameter                   | Required | Description                                                                      |
| --------------------------- | -------- | -------------------------------------------------------------------------------- |
| `configId`                  | Yes      | The [wire configuration](https://www.twisp.com/docs/reference/wire/configuration.md).                         |
| `accountId`                 | Yes      | The customer account to debit. It cannot be one of the configuration's accounts. |
| `amount`                    | Yes      | Decimal dollars, at most two fraction digits, from 0.01 to 9999999999.99.        |
| `debtorName`                | Yes      | The originator's name.                                                           |
| `debtorAccount`             | No       | The originator's account number.                                                 |
| `debtorAddress`             | No       | The originator's address, as JSON (see below).                                   |
| `creditorName`              | Yes      | The beneficiary's name.                                                          |
| `creditorAccount`           | Yes      | The beneficiary's account number, up to 34 characters.                           |
| `creditorAddress`           | No       | The beneficiary's address, as JSON.                                              |
| `creditorRoutingNumber`     | Yes      | The beneficiary bank's ABA routing number.                                       |
| `creditorAgentName`         | No       | The beneficiary bank's name, up to 140 characters.                               |
| `creditorAgentAddress`      | No       | The beneficiary bank's address, as JSON.                                         |
| `remittance`                | No       | Remittance information, up to 140 characters.                                    |
| `endToEndId`                | No       | Your reference, up to 35 characters. Defaults to the UETR without hyphens.       |
| `instructionId`             | No       | Your instruction id (`InstrId`), up to 35 characters.                            |
| `effective`                 | No       | Effective date of the transactions. Defaults to the Fedwire business day.        |
| `metadata`, `entryMetadata` | No       | JSON for the transaction and entry metadata.                                     |

The debtor agent's name and address, the charge bearer and the account scheme come from the [configuration](https://www.twisp.com/docs/reference/wire/configuration.md#outbound-message-fields).

An address is a JSON object with any of `streetName`, `buildingNumber`, `postCode`, `townName`, `countrySubDivision`, `country` (ISO 3166 alpha-2) and `lines` (up to three unstructured lines of 35 characters).

`CREATE`:

1. Builds the wire's pacs.008 and checks it against the Fed usage guidelines. Every problem with the parameters is returned together as `BAD_REQUEST`.
2. Sets the wire's UETR. It is derived from the execution id, so it is stable, and it is returned in the execution context as `uetr`.
3. Posts `SYS_WIRE_OUTBOUND_PENDING_DR`, holding the amount in the customer's pending layer. Velocity controls on the account apply: a control that rejects the posting declines the wire, and `CREATE` fails.
4. Queues the wire for the next [`generateFile`](https://www.twisp.com/docs/reference/wire/file-operations.md#generating-outbound-files).

## Tasks

| Task     | From               | Parameters                               | Ledger                                                                                    |
| -------- | ------------------ | ---------------------------------------- | ----------------------------------------------------------------------------------------- |
| `CREATE` | —                  | See above                                | Posts `SYS_WIRE_OUTBOUND_PENDING_DR`                                                      |
| `SUBMIT` | `CREATE`           | `msgId`, `messageId`                     | None. Records the generated message. Run by `generateFile`.                               |
| `SETTLE` | `SUBMIT`           | `effective`, `metadata`, `entryMetadata` | Voids the hold (`SYS_WIRE_OUTBOUND_PENDING_VOID_CR`), posts `SYS_WIRE_OUTBOUND_SETTLE_DR` |
| `REJECT` | `CREATE`, `SUBMIT` | `reasonCode`, `reasonInfo`               | Voids the hold                                                                            |
| `CANCEL` | `CREATE`           | —                                        | Voids the hold. `generateFile` skips the wire.                                            |
| `RETURN` | `SETTLE`           | `amount`, `reasonCode`, `reasonInfo`     | Posts `SYS_WIRE_OUTBOUND_RETURN_CR`                                                       |

All parameters are optional except where noted for `CREATE` and `SUBMIT`. A parameter a task does not accept is `BAD_REQUEST`. A task that does not follow the wire's current state fails with `INVALID_STATE_TRANSITION` and changes nothing.

`RETURN` may return part of the wire: `amount` defaults to the wire's amount and cannot exceed it. A partial return is recorded in the execution context as `returnAmount`.

You normally run only `CREATE` and, before generation, `CANCEL`. Twisp runs `SUBMIT` during generation and the other tasks when it [processes the Fed's replies](https://www.twisp.com/docs/reference/wire/outbound.md#replies-from-the-fed).

## Replies From the Fed

Process each reply file with [`Mutation.wire.processFile()`](https://www.twisp.com/docs/reference/graphql/mutations.md#wire.process-file). Twisp finds the wire by UETR, or by message id for an admi.002, and runs the task:

| Reply                          | Matched by                                 | Task                                                              |
| ------------------------------ | ------------------------------------------ | ----------------------------------------------------------------- |
| pacs.002 with `ACSC` or `ACCC` | `OrgnlUETR`, then `OrgnlMsgId`             | `SETTLE`                                                          |
| pacs.002 with `RJCT`           | `OrgnlUETR`, then `OrgnlMsgId`             | `REJECT`, with the status reason (such as `E433`) as `reasonCode` |
| pacs.002 with another status   | —                                          | Recorded as `IGNORED`                                             |
| admi.002                       | `RltdRef/Ref`, the rejected message's IMAD | `REJECT`, with the reject reason                                  |
| pacs.004                       | `OrgnlUETR`, then `OrgnlMsgId`             | `RETURN`, with the returned amount and reason                     |

A reply that matches no wire is recorded as `IGNORED`. The exception is a pacs.004: returned funds have arrived, so a pacs.004 that matches no wire is credited to the configuration's exception account as an inbound wire.

A reply that does not apply to the wire's state, such as a second pacs.002 for a settled wire, is recorded as `IGNORED` and changes nothing.

## Balances

For a $25,000.00 wire from a customer account:

| Step                                       | Customer pending | Customer settled |
| ------------------------------------------ | ---------------- | ---------------- |
| `CREATE`                                   | −25,000.00       | 0                |
| `SUBMIT`                                   | −25,000.00       | 0                |
| `SETTLE`                                   | 0                | −25,000.00       |
| `RETURN` of $10,000.00                     | 0                | −15,000.00       |
| or `REJECT` / `CANCEL` instead of `SETTLE` | 0                | 0                |

Postings after the Fed has acted (`SETTLE`, `REJECT`, `RETURN`) are not blocked by velocity controls.
