Closing Accounts

When a customer no longer needs an account, request its closure through the API. Closure is an asynchronous process: Modern Treasury validates the request, moves the Internal Account to pending_closure, and returns closed once the account is terminally closed.

Requirements

Before requesting closure, make sure the account meets each of the following:

  • Zero balance. The available, pending, and posted balances must all be 0. Sweep or withdraw any remaining funds first, and confirm with Retrieving Account Balances.
  • No in-flight transfers. All Payment Orders, Returns, and Reversals on the account must be completed or cancelled.

Request a Closure

Send a PATCH request to the Update Internal Account endpoint with status set to pending_closure. Only pending_closure is accepted for status; any other non-blank value is rejected, and status cannot be combined with another updatable attribute.

curl --request PATCH \
     -u ORGANIZATION_ID:API_KEY \
     --url https://app.moderntreasury.com/api/internal_accounts/<internal_account_id> \
     -H 'content-type: application/json' \
     -d '{
       "status": "pending_closure"
     }'

A successful request returns the full Internal Account with a status of pending_closure. The example below is abridged; see the Internal Account object for every field.

{
  "id": "bf5f1df9-de01-40c2-9040-7ec10170a14c",
  "object": "internal_account",
  "name": "Customer Payment Account",
  "status": "pending_closure",
  "currency": "USD",
  "legal_entity_id": "8f4e2b1c-7d93-4a56-b8e1-2c9f0a3d5e67",
  "parent_account_id": null,
  "counterparty_id": null,
  "live_mode": true,
  "metadata": {},
  "created_at": "2026-01-01T16:30:00Z",
  "updated_at": "2026-02-14T09:15:00Z"
}

Closure States

StatusDescription
pending_closureThe closure request has been accepted and is being processed. The account can no longer originate payments.
closedThe account is terminally closed. It can no longer be used.

An account stays in pending_closure until the closure finishes processing, which can take several business days.

Subscribe to internal_account webhooks to be notified when the closure completes. You will receive an internal_account.closed webhook once the account reaches closed.

Failure Responses

Rejected closures return a 422 with the reason in errors.message and leave the account in its previous status, either active or suspended; a failed request never leaves the account in pending_closure. Errors prefixed with vendor_rejected are surfaced from downstream checks run against the most up-to-date account state.

A non-zero balance:

{
  "errors": {
    "code": "parameter_invalid",
    "message": "vendor_rejected: Account must have a zero balance to be closed",
    "parameter": "base"
  },
  "error_list": [
    {
      "code": "parameter_invalid",
      "message": "vendor_rejected: Account must have a zero balance to be closed",
      "parameter": "base"
    }
  ]
}

In-flight transfers on the account:

{
  "errors": {
    "code": "parameter_invalid",
    "message": "The internal account has in-flight PaymentOrders.",
    "parameter": "internal_account"
  },
  "error_list": [
    {
      "code": "parameter_invalid",
      "message": "The internal account has in-flight PaymentOrders.",
      "parameter": "internal_account"
    }
  ]
}

An account in a state that cannot be closed, such as one that is already closed or still pending activation:

{
  "errors": {
    "code": "parameter_invalid",
    "message": "vendor_rejected: Account is not in a state that can be closed",
    "parameter": "base"
  },
  "error_list": [
    {
      "code": "parameter_invalid",
      "message": "vendor_rejected: Account is not in a state that can be closed",
      "parameter": "base"
    }
  ]
}