> ## Documentation Index
> Fetch the complete documentation index at: https://docs.lead.bank/llms.txt
> Use this file to discover all available pages before exploring further.

# Wires API V2 Migration Guide

> Understand what changed in Wires API V2, how to update your integration, and what you need to complete before the November 16, 2026 Fedwire migration.

Lead is migrating the Wire API from V1 to V2. All partners must migrate to V2 before Lead's migration deadline on November 12, 2026. V1 will be deprecated after the migration window closes.

This guide describes what changed, what you need to update, and the timeline for completing your migration. This page is updated when additional changes occur, with those changes recorded in the Changelog at the top of the page.

<Warning>
  **This guide will be updated as decisions are finalized.**
</Warning>

<Accordion title="Changelog">
  | Date          | Change                            |
  | ------------- | --------------------------------- |
  | July 9, 2026  | Initial version published.        |
  | July 15, 2026 | Added summary of breaking changes |
</Accordion>

## Why This Migration is Required

The November 16, 2026 Fedwire ISO 20022 changes are the forcing function for V2.

As part of this release, Fedwire is replacing fully unstructured postal addresses with a hybrid address format. The new format supports either fully structured addresses or structured addresses with up to two free-form address lines, but at minimum requires country and town\_name as structured fields.

Today, the [V1 create-wire](https://docs.lead.bank/api-reference/endpoint/wire/create-a-wire-v2) request accepts a fully unstructured address (`line_one`, `line_two`, `line_three`). After November 16, that shape will no longer be accepted. V2 introduces a new address object that supports the ISO hybrid address format. Since this changes the request schema, it requires a new API version rather than an in-place update to V1.

V2 also enforces stricter validation on all rail-bound text fields, rejecting carriage returns, line feeds, tabs, and whitespace-only values.

Since this migration already requires a new API version, V2 also introduces a focused set of improvements including corridor classification, consolidated routing identifiers, and enum-based return and rejection reasons so partners only need to migrate once instead of absorbing multiple breaking changes over time.

## Timeline

| Date               | Milestone                           | Required Action                                                                                                                                                |
| :----------------- | :---------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| End of August 2026 | Wire V2 available in Sandbox        | Begin testing against V2 Sandbox APIs and webhooks. Start planning your integration now.                                                                       |
| October 2026       | Wire V2 available in Production     | Partners may begin migrating from V1 to V2 in production. We recommend migrating as soon as V2 is available in production to avoid disrupting wire processing. |
| November 12, 2026  | Migration deadline                  | Complete your migration from V1 to V2 by this date.                                                                                                            |
| November 16, 2026  | Fedwire ISO 20022 v2.0 takes effect | Fedwire removes fully unstructured address support. All wires must be V2-compatible by this point.                                                             |
| February 16, 2027  | V1 wires no longer returnable       | No action required. V1 wires submitted before November 16 can no longer be returned after this date.                                                           |

<Note>
  The detailed migration runbook including the per-program cutover sequence, V1 deprecation timing, and maintenance windows will be shared as the migration plan is finalized. Contact your TAM with questions about your specific timeline.
</Note>

# Summary of Breaking Changes

| **Area**         | **v1**                                    | **v2**                                                        |
| :--------------- | :---------------------------------------- | :------------------------------------------------------------ |
| Create wire      | No `corridor_type`                        | `corridor_type` **required**                                  |
| Routing number   | `creditor_agent.routing_number`           | Removed — use `creditor_agent.local_routing_identifier.value` |
| BIC field        | Optional for any wire                     | Required for international, rejected for domestic             |
| Creditor address | 3 unstructured lines; `line_one` required | `town_name` + `country` required; `line_three` removed        |
| Wire return      | Field `return_code` with ISO 20022 codes  | Field `reason` with human-readable values                     |

## **1. Update Wire Creation (**`POST /v2/wires`**)**

Several fields in the request body have changed. The top-level diff:

```text theme={null}
 {
   "account_number_id": "acn_123",
   "amount": 100000,
   "currency_code": "USD",
+  "corridor_type": "domestic", // [!code ++]
   "creditor_agent": { ... },
   "creditor": { ... },
   "remittance_details": { ... }
 }
```

#### **1a.** `corridor_type `**Is Now Required**

Set to `"domestic"` or `"international"`. This value drives the validation rules for several other fields below.

In addition, you may also include the new optional `ultimate_debtor` object:

```text theme={null}
{
  "corridor_type": "international",
  "ultimate_debtor": { "name": "Acme Corp" }
}
```

#### **1b. Routing Number Moved To** `local_routing_identifier.value`

`creditor_agent.routing_number` no longer exists in v2. Pass the 9-digit ABA routing number through `creditor_agent.local_routing_identifier.value` instead. This field is **required** when `corridor_type` is `"domestic"`.

```text highlight={2} theme={null}
   "creditor_agent": {
-    "routing_number": "021000021" // [!code --]
+    "local_routing_identifier": { // [!code ++]
+      "value": "021000021" // [!code ++]
+    } // [!code ++]
   }
```

The same applies to `instructed_agent` if you use it.

#### **1c.** `business_identifier_code `**(BIC) Is Now Corridor-type Conditional**

In v1, BIC was informally required for international wires. In v2 this is enforced:

* `corridor_type: "international"` → `business_identifier_code` **required**
* `corridor_type: "domestic"` → `business_identifier_code` **not accepted**

```text theme={null}
// domestic — use local_routing_identifier, no BIC
creditor_agent: { local_routing_identifier: { value: '021000021' } }

// international — use BIC, no routing number
creditor_agent: { business_identifier_code: 'CHASUS33' }
```

#### **1d.** `creditor.address `**Is Restructured**

v2 adopts an ISO 20022 hybrid address format. `line_three` is removed and two new **required** fields are added: `town_name` and `country`.

| **Field**              | **v1**                 | **v2**                                         |
| :--------------------- | :--------------------- | :--------------------------------------------- |
| `line_one`             | Required, max 35 chars | Optional, max 70 chars                         |
| `line_two`             | Optional, max 35 chars | Optional, max 70 chars                         |
| `line_three`           | Optional, max 35 chars | **Removed**                                    |
| `town_name`            | —                      | **Required**, max 35 chars                     |
| `country_sub_division` | —                      | Optional, max 35 chars                         |
| `post_code`            | —                      | Optional, max 16 chars                         |
| `country`              | —                      | **Required**, ISO 3166-1 alpha-2 (e.g. `"US"`) |

```text theme={null}
   "address": {
+    "line_one": "123 Main St",
+    "line_two": "Suite 400",
	"line_three": "IL, USA", // [!code --]
+    "town_name": "Springfield", // [!code ++]
+    "country_sub_division": "IL", // [!code ++]
+    "post_code": "62701", // [!code ++]
+    "country": "US"
   }
```

> If you were putting city/state/country into `line_two` or `line_three`, split those values into the new structured fields.

### **1e. Read-only Fields Removed From Request Schemas**

In v1, `payment_identifiers` and `remittance_details` included several `readOnly` fields that were silently ignored in requests. In v2 these are absent from the request schema entirely — sending them will cause an error. If your code serializes a full wire object back into a create request, strip these fields first.

`payment_identifiers `**— only** `end_to_end_identification `**is accepted; remove:**

* `message_identification`, `uetr`, `instruction_identification`, `return_identification`

`remittance_details `**— only** `message_to_creditor `**and** `transfer_purpose `**are accepted; remove:**

* `payment_notification`, `message_to_receiving_fi`, `fi_to_fi_message`

## **2. Update Wire Return Reasons**

`POST /v2/wires/{wire_id}/return` renames `return_code` to `reason` and replaces ISO 20022 codes with human-readable strings.

**v1 request:**

```text theme={null}
{
  "return_code": "AC06" // [!code --]
}
```

**v2 request:**

```text theme={null}
{
  "reason": "account_blocked" // [!code ++]
}
```

### **Full Mapping**

| **v1** `return_code` | **v2** `reason`          |
| :------------------- | :----------------------- |
| `AC06`               | `account_blocked`        |
| `AM09`               | `wrong_amount`           |
| `BE01`               | `creditor_name_mismatch` |
| `FOCR`               | `honor_return_request`   |
| `FR01`               | `fraud_suspected`        |
| `MS02`               | `missing_debtor_data`    |
| `RR02`               | `creditor_request`       |
| `NARR`               | `narrative`              |
| `RR03`               | `missing_creditor_data`  |

```text theme={null}
// v1
await client.post(`/v1/wires/${wireId}/return`, {
  return_code: 'AC06',
  return_additional_information: 'Account is frozen',
});

// v2
await client.post(`/v2/wires/${wireId}/return`, {
  reason: 'account_blocked',
  return_additional_information: 'Account is frozen',
});
```

## **3. Handle New Response Fields**

v2 wire responses include new fields. You don't have to use them, but you should not break if they appear.

```text theme={null}
const wire = await getWire(wireId);

// New in v2 — safe to use, ignore if not needed
wire.corridor_type       // "domestic" | "international"
wire.core_transaction_ids // ["ctx_abc", "ctx_def"]
wire.initiating_party    // object — the party that initiated the wire
```

## 4. V1 Return Window

Wires submitted through the V1 API before the migration deadline will remain returnable for 3 months after November 16. After February 16, 2027, V1 wires can no longer be returned.

If you have V1 wires that may need to be returned, submit any return requests before that window closes.

# Detailed Changes

## Wire V2 Object

The V2 wire object keeps the overall V1 shape and field names, with a focused set of ISO-driven additions and changes. The most significant differences from V1 are the hybrid address model, the consolidation of routing numbers into `local_routing_identifier`, the new `corridor_type` and `initiating_party` fields, and the move from raw ISO codes to normalized enums on return reasons.

### Key Changes vs. V1

| Field                                      | V1                                                               | V2                                                                                                                                                                                                                                       |
| :----------------------------------------- | :--------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `corridor_type`                            | Not present                                                      | New -`domestic` or `international`. For outgoing wires, set from the `POST /v1/wires` request; for incoming wires, derived from the payload and agent chain.                                                                             |
| `status`                                   | Full status set                                                  | No change for now. See [Statuses](#statuses) for planned 2027 deprecations.                                                                                                                                                              |
| `*_agent.local_routing_identifier`         | Not present                                                      | New - `{ scheme, value }`, replaces `routing_number`. For domestic wires, `scheme` is `USABA` and `value` is the 9-digit ABA. Applies to `debtor_agent`, `creditor_agent`, `instructing_agent`, `instructed_agent`, and charging agents. |
| `*_agent.routing_number`                   | Present on all agents                                            | Removed; replaced by `local_routing_identifier`.                                                                                                                                                                                         |
| `initiating_party`                         | Not present                                                      | New - standard wire-party object. On outgoing wires, `initiating_party.name` is auto-populated with the partner's name. On incoming wires, populated from the ISO payload when available.                                                |
| `ultimate_debtor`                          | Response only                                                    | Now client-settable on create.                                                                                                                                                                                                           |
| `*.address` (response)                     | Unstructured (`line_one`–`line_three`)                           | No change. Response keeps the existing shape, including `line_three`, to support legacy V1 wire data.                                                                                                                                    |
| `remittance_details.transfer_purpose.type` | Outgoing purpose values only                                     | Enum expanded to add incoming transfer-purpose values previously omitted to avoid a breaking change.                                                                                                                                     |
| `return.code`                              | Raw ISO code                                                     | Removed. Use `return.reason` instead.                                                                                                                                                                                                    |
| `return.reason`                            | Enum (mapped ISO reasons)                                        | Full ISO reason set, plus a new `other` value for unmapped incoming codes. When `other`, the raw ISO code is placed in `return.additional_information` as `"ISO Code: <code>; <details>"`.                                               |
| `rejection.reason`                         | Enum                                                             | Reason set revised for incoming and outgoing rejections.                                                                                                                                                                                 |
| `return_requests`                          | Not present in V1 today; being added to V1 before the V2 rollout | No V2-specific change.                                                                                                                                                                                                                   |

## Statuses

Wire statuses are unchanged from V1 for this migration. The full status set (`created`, `scheduled`, `processing`, `posted`, `under_review`, `rejected`, `canceled`, `cancel_pending`) continues to be returned as it is today.

<Tip>
  **Planned for 2027**

  The wire status lifecycle changes are deferred until after the V2 rollout. Partners will receive at least three months' notice before any status is removed. No action is required for the V2 migration itself.
</Tip>

The planned changes differ by direction:

* **Outgoing wires:** `scheduled`, `processing`, and `cancel_pending` will be deprecated, leaving the lifecycle `created` → `under_review` → `posted` / `rejected` / `canceled`.
* **Incoming wires:** `under_review` will become an active status (and the `wire.under_review` webhook will begin firing for incoming wires), leaving the lifecycle `under_review` → `posted` / `rejected`.

## Example `Wire V2` Object

```json theme={null}
{
  "id": "wire_xyz123",
  "account_number_id": "account_number_xyz123",
  "created_at": "2026-05-25T10:00:00Z",
  "updated_at": "2026-05-25T10:05:00Z",
  "settlement_date": "2026-05-25",
  "direction": "outgoing",
  "type": "transfer",
  "corridor_type": "domestic",
  "status": "posted",
  "amounts": {
    "settlement_amount": 10000,
    "settlement_currency_code": "USD",
    "instructed_amount": 10000,
    "instructed_currency_code": "USD",
    "instructed_to_settlement_exchange_rate": "1"
  },
  "debtor": {
    "name": "Alex Smith",
    "account_identifier": { "type": "account_number", "value": "..." },
    "address": {
      "line_one": "string | null",
      "line_two": "string | null",
      "line_three": "string | null",
      "town_name": "string | null",
      "country_sub_division": "string | null",
      "post_code": "string | null",
      "country": "string | null"
    }
  },
  "debtor_agent": {
    "business_identifier_code": "string | null",
    "name": "string | null",
    "local_routing_identifier": { "scheme": "USABA", "value": "021000021" },
    "address": { "...": "..." }
  },
  "instructing_agent": {
    "name": "Lead Bank",
    "business_identifier_code": "string | null",
    "local_routing_identifier": { "scheme": "USABA", "value": "101019644" }
  },
  "instructed_agent": {
    "name": "JPMorgan Chase Bank",
    "business_identifier_code": "CHASUS33",
    "local_routing_identifier": { "scheme": "USABA", "value": "021000021" }
  },
  "creditor_agent": {
    "business_identifier_code": "CHASUS33",
    "name": "JPMorgan Chase Bank",
    "local_routing_identifier": { "scheme": "USABA", "value": "021000021" },
    "address": { "...": "..." }
  },
  "creditor": {
    "name": "Example Beneficiary Inc.",
    "account_identifier": { "type": "account_number", "value": "..." },
    "address": {
      "line_one": "123 Main St",
      "line_two": "Suite 100",
      "line_three": null,
      "town_name": "Kansas City",
      "country_sub_division": "MO",
      "post_code": "64105",
      "country": "US"
    }
  },
  "initiating_party": {
    "name": "Your Company Name",
    "account_identifier": { "type": "enum", "value": "string" },
    "address": { "...": "..." }
  },
  "ultimate_debtor": { "name": "John Smith" },
  "ultimate_creditor": {},
  "other_agents": {
    "previous_instructing_agent_one": {},
    "previous_instructing_agent_two": {},
    "previous_instructing_agent_three": {},
    "intermediary_agent_one": {},
    "intermediary_agent_two": {},
    "intermediary_agent_three": {}
  },
  "payment_identifiers": {
    "message_identification": "string | null",
    "end_to_end_identification": "string | null",
    "uetr": "string | null",
    "instruction_identification": "string | null",
    "return_identification": "string | null"
  },
  "remittance_details": {
    "payment_notification": "string | null",
    "message_to_creditor": "string | null",
    "message_to_receiving_fi": "string | null",
    "fi_to_fi_message": "string | null",
    "transfer_purpose": { "type": "enum", "other_details": "string | null" }
  },
  "charges": {
    "charge_bearer": "enum | null",
    "breakdown": [
      { "amount": "string", "currency_code": "string", "charging_agent": {} }
    ]
  },
  "related_wires": {
    "original_wire_id": "wire_xyz321 | null",
    "return_wire_ids": ["wire_xyz456"]
  },
  "return_requests": [
    {
      "status": "response_needed",
      "reason": "customer_requested",
      "details": "ISO Code: CUST; Beneficiary has not received funds",
      "deadline": "2026-06-10T23:30:00-04:00",
      "resolution": {
        "resolved_at": null,
        "resolved_by": null,
        "rejection_reason": null,
        "rejection_details": null
      },
      "created_at": "2026-05-26T09:00:00Z"
    }
  ],
  "return": {
    "reason": "enum",
    "additional_information": "string | null"
  },
  "rejection": {
    "reason": "enum",
    "additional_information": "string | null",
    "message_identification": "string | null"
  },
  "metadata": {}
}
```

## Detailed API Changes by Endpoint

**Create a Wire:** `POST /v2/wires`

| Field                                     | V1                                                  | V2                                                                                                                                              |
| :---------------------------------------- | :-------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------- |
| URL path                                  | `POST /v1/wires`                                    | `POST /v2/wires`                                                                                                                                |
| `corridor_type`                           | Not present                                         | New required enum - `domestic` or `international`. Determines which `creditor_agent` routing fields are required.                               |
| `creditor_agent.routing_number`           | 9-digit ABA                                         | Removed; replaced by `creditor_agent.local_routing_identifier.value`. Required when `corridor_type=domestic`. Scheme is auto-populated by Lead. |
| `creditor_agent.business_identifier_code` | Required for international wires                    | Still required for international wires; now keyed to `corridor_type=international`. Not accepted when `corridor_type=domestic`.                 |
| `instructed_agent.routing_number`         | Optional                                            | Removed; replaced by `instructed_agent.local_routing_identifier.value`.                                                                         |
| `creditor.address`                        | `line_one`, `line_two`, `line_three` (unstructured) | Hybrid address. `line_three` removed. `line_one` and `line_two` now optional (max 70 chars each).                                               |
| `creditor.address.town_name`              | Not present                                         | New - required (max 35 chars).                                                                                                                  |
| `creditor.address.country`                | Not present                                         | New - required (ISO 3166-1 alpha-2, uppercase).                                                                                                 |
| `creditor.address.country_sub_division`   | Not present                                         | New - optional.                                                                                                                                 |
| `creditor.address.post_code`              | Not present                                         | New - optional.                                                                                                                                 |
| `ultimate_debtor.name`                    | Not settable on create                              | New - optional (max 35 chars). Useful for nested payments where the ultimate customer differs from the debtor.                                  |
| Text field validations                    | Standard                                            | New ISO character-set validations on rail-bound text fields. CR, LF, Tab, and whitespace-only values are rejected.                              |
| Response                                  | WireV1                                              | WireV2                                                                                                                                          |

**V2 Request Example**

```json theme={null}
{
  "account_number_id": "account_number_xyz123",
  "corridor_type": "domestic",
  "amount": 10000,
  "currency_code": "USD",
  "creditor_agent": {
    "local_routing_identifier": { "value": "021000021" }
  },
  "instructed_agent": {
    "business_identifier_code": "BOFAUS3N",
    "local_routing_identifier": { "value": "026009593" }
  },
  "creditor": {
    "name": "Example Beneficiary Inc.",
    "account_identifier": {
      "type": "account_number",
      "value": "GB29NWBK60161331926819"
    },
    "address": {
      "line_one": "123 Main St",
      "line_two": "Suite 100",
      "town_name": "Kansas City",
      "country_sub_division": "MO",
      "post_code": "64105",
      "country": "US"
    }
  },
  "ultimate_debtor": { "name": "John Smith" },
  "remittance_details": {
    "message_to_creditor": "Payment for invoice 12345",
    "transfer_purpose": { "type": "enum", "other_details": "string" }
  },
  "payment_identifiers": { "end_to_end_identification": "E2E-20260525-001" },
  "metadata": { "client_reference_id": "abc123" }
}
```

**List All Wires:** `GET /v2/wires`

| Field                  | V1                                                                                                   | V2                                                   |
| :--------------------- | :--------------------------------------------------------------------------------------------------- | :--------------------------------------------------- |
| URL path               | `GET /v1/wires`                                                                                      | `GET /v2/wires`                                      |
| `corridor_type` filter | Not present                                                                                          | New query parameter - `domestic` or `international`. |
| Other filters          | `account_number_id`, `direction`, `status`, `created_at`, `limit`, `starting_after`, `ending_before` | No change.                                           |
| Response               | Array of WireV1 objects                                                                              | Array of WireV2 objects.                             |

**Retrieve a Wire:** `GET /v2/wires/{wire_id}`

| Field    | V1                        | V2                        |
| :------- | :------------------------ | :------------------------ |
| URL path | `GET /v1/wires/{wire_id}` | `GET /v2/wires/{wire_id}` |
| Request  | No change                 | No change.                |
| Response | WireV1                    | WireV2.                   |

**Update a Wire:** `PATCH /v2/wires/{wire_id}`

| Field    | V1                          | V2                          |
| :------- | :-------------------------- | :-------------------------- |
| URL path | `PATCH /v1/wires/{wire_id}` | `PATCH /v2/wires/{wire_id}` |
| Request  | `metadata` only             | No change.                  |
| Response | WireV1                      | WireV2.                     |

**Cancel a Wire:** `POST /v2/wires/{wire_id}/cancel`

| Field    | V1                                | V2                                |
| :------- | :-------------------------------- | :-------------------------------- |
| URL path | `POST /v1/wires/{wire_id}/cancel` | `POST /v2/wires/{wire_id}/cancel` |
| Request  | No change                         | No change.                        |
| Response | WireV1                            | WireV2.                           |

**Return a Wire:** `POST /v2/wires/{wire_id}/return`

| Field                  | V1                                                                | V2                                                                                                                                                                                                                                                        |
| :--------------------- | :---------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| URL path               | `POST /v1/wires/{wire_id}/return`                                 | `POST /v2/wires/{wire_id}/return`                                                                                                                                                                                                                         |
| Target wire            | Incoming transfer wires only                                      | May also be called on incoming return wires to support return-of-a-return. Available only after the November 16, 2026 Fedwire ISO release.                                                                                                                |
| Return reason          | `return_code` - raw ISO code (e.g. `AC06`, `NARR`)                | `return_code` removed. Replaced by `reason` - a normalized enum: `account_blocked`, `wrong_amount`, `creditor_name_mismatch`, `honor_return_request`, `fraud_suspected`, `creditor_request`, `narrative`, `missing_debtor_data`, `missing_creditor_data`. |
| Additional information | `return_additional_information`, required when `return_code=NARR` | `return_additional_information`, required when `reason=narrative`. Max 105 chars; new ISO character-set validations applied.                                                                                                                              |
| Amount                 | Optional (defaults to original wire amount)                       | No change.                                                                                                                                                                                                                                                |
| Response               | WireV1                                                            | WireV2.                                                                                                                                                                                                                                                   |

**Request Return:** `POST /v2/wires/{wire_id}/request_return`

For the full request and response schema, see the [Return Requests](/products/wire/return-requests) guide.

| Field       | V1                                        | V2                                                                                                                                         |
| :---------- | :---------------------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------- |
| URL path    | `POST /v1/wires/{wire_id}/request_return` | `POST /v2/wires/{wire_id}/request_return`                                                                                                  |
| Target wire | Transfer wires                            | May also be called on incoming return wires to support return-of-a-return. Available only after the November 16, 2026 Fedwire ISO release. |

**Reject Return Request:** `POST /v2/wires/{wire_id}/reject_return_request`

For the full request and response schema, see the [Return Requests](/products/wire/return-requests) guide.

| Field    | V1                                               | V2                                               |
| :------- | :----------------------------------------------- | :----------------------------------------------- |
| URL path | `POST /v1/wires/{wire_id}/reject_return_request` | `POST /v2/wires/{wire_id}/reject_return_request` |
| Behavior | No change                                        | No change.                                       |
