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

# Release Payments

export const ParamList = ({items = [], is_child = false}) => {
  return items.map(item => {
    const field_props = {
      id: Math.random().toString(),
      body: item.name,
      name: item.name,
      type: item.type,
      required: item.required
    };
    const enums = item.enums || [];
    const items = item.items || [];
    const has_items = items?.length > 0;
    const has_enums = enums?.length > 0;
    const should_default_open = item.defaultOpen || false;
    const render_child_item = () => {
      const child_props = {
        title: has_enums ? "Possible enum values" : "properties"
      };
      if (should_default_open) child_props.defaultOpen = true;
      const has_inline_enums = has_enums && enums.every(enum_item => typeof enum_item === 'string') && enums.map((enum_item, idx) => {
        const is_last = idx === enums.length - 1;
        const is_2nd_to_last = idx === enums.length - 2;
        return <>
            <code>{enum_item}</code>
            {is_last && ''}
            {is_2nd_to_last && ' or '}
            {!is_last && !is_2nd_to_last && ', '}
          </>;
      });
      const enum_list = has_enums && !has_inline_enums && <Accordion {...child_props}>
          {enums.map((enum_item, index) => <div key={`enum-${index}`}>
              <code>{enum_item.name}</code>
              <br />
              <p>{enum_item.description}</p>
            </div>)}
        </Accordion>;
      const item_list = has_items && <Expandable {...child_props}>
          <ParamList items={items || []} is_child />
        </Expandable>;
      return <>
          <p>
            {item.description}
            {has_inline_enums && [has_inline_enums.length > 1 ? ' One of ' : ' Must be ', ...has_inline_enums]}
          </p>

          {enum_list}
          {item_list}
        </>;
    };
    return is_child ? <ResponseField {...field_props}>{render_child_item()}</ResponseField> : <ParamField {...field_props}>{render_child_item()}</ParamField>;
  });
};

Release the payments for a confirmed [Balance Transfer](/opal/balance_transfer/overview) session. Method creates one [Payment](/2025-07-04/reference/payments/overview) per allocated account, from the source account to that liability account, for the allocated amount.

<Note>
  This endpoint requires your secret API key. Requests authenticated with an
  Opal token are rejected. Sessions that do not belong to your team return
  `404`.
</Note>

## Behavior

* The session must have a `bt.payout_status` of `pending_release`. Calling this endpoint before the user confirms returns `BT_NO_ALLOCATIONS`.
* Method re-checks the allocations, the source account, and every destination account before any money moves. If a check fails, the request returns an error, the session stays in `pending_release`, and you can retry after resolving the issue.
* Releasing is idempotent. Calling this endpoint on a `released` session returns the session unchanged and creates no new payments.
* Each payment is created independently. If Method cannot create the payment for one account, that account's entry in `bt.payment_ids` is `null` and the other payments still go out. A released session cannot be released again, so handle any `null` entry separately.
* Payments use the description configured for your team. The description cannot be set in the request. Contact your CSM to set or change it.

## Path Parameters

<ParamList
  items={[
{
  name: "session_id",
  type: "string",
  required: true,
  description: "ID of the Opal session, returned when you create a token.",
},
]}
/>

## Body

<ParamList
  items={[
{
  name: "action",
  type: "enum",
  required: true,
  description: "The action to take on the session.",
  enums: ["release_payments"],
},
{
  name: "data",
  type: "object",
  required: false,
  description: "Options for the action.",
  items: [
    {
      name: "data.source",
      type: "string",
      required: false,
      description:
        "ID of the Account that funds the payments. If omitted, Method uses the default source account configured for your team. If neither is set, the request fails with BT_MISSING_SOURCE.",
    },
  ],
},
]}
/>

## Returns

Returns the updated Opal session. See [Retrieve Session](/2025-07-04/reference/opal/retrieve_session) for the full list of fields. After a successful release, `bt.payout_status` is `released` and `bt.payment_ids` maps each allocated account to its Payment ID.

## Errors

Errors use the `INVALID_REQUEST` type with one of the following sub types.

| Sub type                     | When it occurs                                                                           |
| ---------------------------- | ---------------------------------------------------------------------------------------- |
| `INVALID_MODE_CONFIG`        | The session is not a balance transfer session.                                           |
| `BT_NO_ALLOCATIONS`          | The user has not confirmed allocations yet.                                              |
| `BT_MISSING_SOURCE`          | No `data.source` was provided and no default source account is configured for your team. |
| `BT_ACCOUNT_NOT_PAYABLE`     | An allocated account can no longer receive payments.                                     |
| `BT_AMOUNT_OUT_OF_BOUNDS`    | An allocation exceeds `maximum_payment`.                                                 |
| `BT_ALLOCATIONS_EXCEED_LOAN` | The total allocated exceeds `loan_amount`.                                               |
| `BT_RESIDUAL_EXCEEDS_MAX`    | The unallocated amount exceeds `residual_amount_max`.                                    |

An invalid source account returns the same errors as [Create a Payment](/2025-07-04/reference/payments/create).

<RequestExample>
  ```bash cURL theme={null}
  curl https://production.methodfi.com/opal/sessions/osess_zde3mW34pEHqV \
    -X POST \
    -H "Method-Version: 2025-07-04" \
    -H "Authorization: Bearer sk_WyZEWVfTcH7GqmPzUPk65Vjc" \
    -H "Content-Type: application/json" \
    -d '{
      "action": "release_payments",
      "data": {
        "source": "acc_Zc4F2aTLt8CBt"
      }
    }'
  ```
</RequestExample>

<ResponseExample>
  ```json theme={null}
  {
    "success": true,
    "data": {
      "id": "osess_zde3mW34pEHqV",
      "mode": "balance_transfer",
      "bt": {
        "loan_amount": 1000000,
        "minimum_payment": 5000,
        "maximum_payment": 500000,
        "residual_amount_max": 150000,
        "allocations": {
          "acc_hmap9mbgfLcf9": 500000,
          "acc_YXDrjADGjC76U": 350000
        },
        "payout_status": "released",
        "payment_ids": {
          "acc_hmap9mbgfLcf9": "pmt_VeCfmkwGKb",
          "acc_YXDrjADGjC76U": "pmt_rPrDPEwyCVUcm"
        },
        "released_at": "2026-09-24T14:05:21.118Z",
        "completed": true
      },
      "created_at": "2026-09-23T22:31:40.312Z",
      "updated_at": "2026-09-24T14:05:21.402Z"
    },
    "message": null
  }
  ```
</ResponseExample>
