---
title: "Create an internal account"
method: POST
path: "/internal-accounts"
tags: ["Internal Accounts"]
---

# Create an internal account

`POST /internal-accounts`

Create a rule-based internal account.

A rule-based account is an additional account number for an account holder
that already holds an account in the same currency. It carries a routing
rule: every payment that settles into it is attributed to that account
number and then swept to the rule's destination, so you can issue one number
per payer and reconcile incoming payments without matching on remittance
text.

Only `RULE_BASED` accounts can be created here. `INTERNAL_FIAT`,
`INTERNAL_CRYPTO`, and `EMBEDDED_WALLET` accounts are provisioned
automatically when an account holder is created or approved.

The response carries the account's own `fundingPaymentInstructions` — the
routable number payers send to. Rule-based accounts are currently available
in `USD`, for individual customers, and must be enabled for your platform
before this endpoint accepts requests.

Sandbox platforms can create rule-based accounts and exercise the whole
flow. The account number is generated locally rather than issued by a
partner bank, and `POST /sandbox/internal-accounts/{accountId}/fund` stands
in for a settled deposit — funding the account triggers its sweep just as a
real deposit would.

Creating an account mints a new account number that cannot be reversed, so
an `Idempotency-Key` header is required. A retry carrying the same key
returns the account created by the first request with a `200` instead of a
`201`; reusing a key for a materially different account is rejected with
`409`.

## Headers

- `Idempotency-Key` string, required

## Request body

- InternalAccountCreateRequest — Request body for `POST /internal-accounts`. Only `RULE_BASED` accounts can be created today, and they are rejected without a `sweepRule` — the type and its rule are created together or not at all.
  - `customerId` string — The customer the account is created for. Omit it to create a platform-owned account. The account holder must already have a verified account in the same currency, which is where funds land when a sweep cannot be completed. Platform-owned rule-based accounts are not available yet, so omitting this is currently rejected.
  - `type` 'INTERNAL_FIAT' | 'INTERNAL_CRYPTO' | 'EMBEDDED_WALLET' | 'RULE_BASED', required — Classification of an internal account. - `INTERNAL_FIAT`: A Grid-managed fiat holding account (for example, the USD holding account used as the source for Payouts flows). - `INTERNAL_CRYPTO`: A Grid-managed crypto holding account denominated in a stablecoin such as USDC. - `EMBEDDED_WALLET`: A self-custodial Embedded Wallet provisioned for the customer. Outbound transfers require a session signature produced by the customer's device — see the Embedded Wallets guide. - `RULE_BASED`: An additional account number for an existing account holder, with a routing rule attached, so incoming payments can be attributed to a specific payer and swept automatically. Created with `POST /internal-accounts`.
  - `currency` string, required — Currency code the account is denominated in (ISO 4217). Rule-based accounts are currently available in `USD` only.
  - `label` string — Your own name for the account, echoed back on reads. Useful for identifying which payer the account was issued for.
  - `sweepRule` SweepRuleRequest — The routing rule attached to a rule-based account. Every payment that settles into the account is swept to the rule's destination, carrying the payment metadata configured here.
    - `destination` SweepRuleDestinationRequest, required — The account a rule-based account sweeps its incoming payments to.
      - `accountId` string, required — Reference to the account that receives the swept funds. May be an external account or another internal account, but never a `RULE_BASED` internal account — that account's own rule would sweep the funds on again. The destination may be denominated in a different currency, in which case the sweep is converted at the prevailing rate.
      - `paymentRail` 'ACH' | 'ACH_COLOMBIA' | 'BANK_TRANSFER' | 'BRE_B' | 'CIPS' | 'FAST' | 'FASTER_PAYMENTS' | 'FEDNOW' | 'INSTAPAY' | 'MOBILE_MONEY' | 'NEFT' | 'PAYNOW' | 'PESONET' | 'PIX' | 'RTGS' | 'RTP' | 'SEPA' | 'SEPA_INSTANT' | 'SPEI' | 'SWIFT' | 'UNIONPAY' | 'UPI' | 'WIRE' — The payment rail used for the transfer. Payment rails represent the underlying payment network or system used to move funds between accounts.
    - `purposeOfPayment` 'GIFT' | 'SELF' | 'GOODS_OR_SERVICES' | 'EDUCATION' | 'HEALTH_OR_MEDICAL' | 'REAL_ESTATE_PURCHASE' | 'TAX_PAYMENT' | 'LOAN_PAYMENT' | 'UTILITY_BILL' | 'DONATION' | 'TRAVEL' | 'FAMILY_SUPPORT' | 'SALARY_PAYMENT' | 'OTHER' — The purpose of the payment. This may be required when sending to certain geographies (e.g. India).
    - `description` string — Free-form description recorded on each sweep. Not delivered to the recipient; use `remittanceInformation` for that.
    - `remittanceInformation` string — Free-form information that travels with each sweep to the recipient. The field this populates depends on the payment rail: for ACH it populates the Addenda record, for FedNow and RTP it populates the remittanceInformation field, and for wires it populates the OBI (Originator to Beneficiary Information) / beneficiary information. Only printable ASCII characters are accepted, because the underlying rails carry nothing else.

## Response `200`

The `Idempotency-Key` was already used to create this account. The account created by the first request is returned unchanged.

- InternalAccount
  - `id` string, required — The ID of the internal account
  - `customerId` string — The ID of the customer associated with the internal account. If this field is empty, the internal account belongs to the platform.
  - `type` 'INTERNAL_FIAT' | 'INTERNAL_CRYPTO' | 'EMBEDDED_WALLET' | 'RULE_BASED', required — Classification of an internal account. - `INTERNAL_FIAT`: A Grid-managed fiat holding account (for example, the USD holding account used as the source for Payouts flows). - `INTERNAL_CRYPTO`: A Grid-managed crypto holding account denominated in a stablecoin such as USDC. - `EMBEDDED_WALLET`: A self-custodial Embedded Wallet provisioned for the customer. Outbound transfers require a session signature produced by the customer's device — see the Embedded Wallets guide. - `RULE_BASED`: An additional account number for an existing account holder, with a routing rule attached, so incoming payments can be attributed to a specific payer and swept automatically. Created with `POST /internal-accounts`.
  - `status` 'PENDING' | 'ACTIVE' | 'CLOSED' | 'FROZEN' | 'FAILED', required — Status of a Grid internal account. The status determines whether the account can send or receive payments. - `PENDING`: The account is under review and is being provisioned. The account cannot send or receive payments until provisioning completes. - `ACTIVE`: The account is ready to send and receive payments. - `CLOSED`: The account cannot send or receive payments. A customer can initiate the closing of an internal account, after which the account transitions to this status. - `FROZEN`: The account cannot send or receive payments. Grid may freeze an account in response to compliance or fraud signals; payments are blocked while the account remains frozen. - `FAILED`: The account could not be provisioned. Grid was unable to create the underlying account, so it cannot send or receive payments and requires remediation.
  - `balance` CurrencyAmount, required
    - `amount` integer, required — Amount in the smallest unit of the currency (e.g., cents for USD/EUR, satoshis for BTC)
    - `currency` Currency, required
      - `code` string — Three-letter currency code (ISO 4217) for fiat currencies. Some cryptocurrencies may use their own ticker symbols (e.g. "BTC" for Bitcoin, "USDC" for USDC, etc.)
      - `name` string — Full name of the currency
      - `symbol` string — Symbol of the currency
      - `decimals` integer — Number of decimal places for the currency
  - `totalBalance` CurrencyAmount, required
    - `amount` integer, required — Amount in the smallest unit of the currency (e.g., cents for USD/EUR, satoshis for BTC)
    - `currency` Currency, required
      - `code` string — Three-letter currency code (ISO 4217) for fiat currencies. Some cryptocurrencies may use their own ticker symbols (e.g. "BTC" for Bitcoin, "USDC" for USDC, etc.)
      - `name` string — Full name of the currency
      - `symbol` string — Symbol of the currency
      - `decimals` integer — Number of decimal places for the currency
  - `fundingPaymentInstructions` PaymentInstructions[], required — Payment instructions for funding the account — unresolved $ref
  - `label` string — The platform-supplied label recorded when the account was created. Null for accounts that carry none.
  - `sweepRule` SweepRule — The routing rule attached to a rule-based account. Returned on the account rather than as a resource of its own, because the rule has no lifecycle apart from the account.
    - `destination` SweepRuleDestination, required — Where a rule-based account's credits are swept.
      - `accountId` string, required — The account that receives the swept funds.
      - `paymentRail` 'ACH' | 'ACH_COLOMBIA' | 'BANK_TRANSFER' | 'BRE_B' | 'CIPS' | 'FAST' | 'FASTER_PAYMENTS' | 'FEDNOW' | 'INSTAPAY' | 'MOBILE_MONEY' | 'NEFT' | 'PAYNOW' | 'PESONET' | 'PIX' | 'RTGS' | 'RTP' | 'SEPA' | 'SEPA_INSTANT' | 'SPEI' | 'SWIFT' | 'UNIONPAY' | 'UPI' | 'WIRE' — The payment rail used for the transfer. Payment rails represent the underlying payment network or system used to move funds between accounts.
    - `minimumAmount` CurrencyAmount
      - `amount` integer, required — Amount in the smallest unit of the currency (e.g., cents for USD/EUR, satoshis for BTC)
      - `currency` Currency, required
        - `code` string — Three-letter currency code (ISO 4217) for fiat currencies. Some cryptocurrencies may use their own ticker symbols (e.g. "BTC" for Bitcoin, "USDC" for USDC, etc.)
        - `name` string — Full name of the currency
        - `symbol` string — Symbol of the currency
        - `decimals` integer — Number of decimal places for the currency
    - `maximumAmount` CurrencyAmount
      - `amount` integer, required — Amount in the smallest unit of the currency (e.g., cents for USD/EUR, satoshis for BTC)
      - `currency` Currency, required
        - `code` string — Three-letter currency code (ISO 4217) for fiat currencies. Some cryptocurrencies may use their own ticker symbols (e.g. "BTC" for Bitcoin, "USDC" for USDC, etc.)
        - `name` string — Full name of the currency
        - `symbol` string — Symbol of the currency
        - `decimals` integer — Number of decimal places for the currency
    - `purposeOfPayment` 'GIFT' | 'SELF' | 'GOODS_OR_SERVICES' | 'EDUCATION' | 'HEALTH_OR_MEDICAL' | 'REAL_ESTATE_PURCHASE' | 'TAX_PAYMENT' | 'LOAN_PAYMENT' | 'UTILITY_BILL' | 'DONATION' | 'TRAVEL' | 'FAMILY_SUPPORT' | 'SALARY_PAYMENT' | 'OTHER' — The purpose of the payment. This may be required when sending to certain geographies (e.g. India).
    - `description` string — Free-form description recorded on each sweep. Not delivered to the recipient.
    - `remittanceInformation` string — Free-form information that travels with each sweep to the recipient.
    - `platformFeeOverride` PlatformFeeOverride — Overrides the platform-collected fee for this transaction. When present, it replaces any configured platform-collected fees that would otherwise apply to the transaction. Currently only supported when the quote's source currency is USD; the fixed fee must be denominated in the source currency.
      - `platformFixedFee` FixedFee, required — Fixed fee charged per transaction.
        - `amount` integer, required — Fee amount in the smallest unit of the fixed fee's `currency` (e.g., cents for USD).
        - `currency` string, required — Three-letter currency code (ISO 4217) the fixed fee is denominated in. Some cryptocurrencies may use their own ticker symbols (e.g. "BTC" for Bitcoin, "USDC" for USDC, etc.)
      - `platformVariableFeeBps` integer, required — Variable fee in basis points (1 bps = 0.01%) to apply to the transaction's source-currency amount.
  - `privateEnabled` boolean — Whether wallet privacy is enabled for the Embedded Wallet. Only present for `EMBEDDED_WALLET` internal accounts.
  - `createdAt` string, date-time, required — Timestamp when the internal account was created
  - `updatedAt` string, date-time, required — Timestamp when the internal account was last updated

## Other responses

- `201` — Internal account created. `fundingPaymentInstructions` carries the account's own number.
- `400` — Bad request. Returned when `type` is not `RULE_BASED`, when `sweepRule` is missing, when the currency is not supported for rule-based accounts, when the account holder has no account in that currency yet, when the destination cannot accept the requested payment rail, and for general invalid parameters.
- `401` — Unauthorized
- `403` — Forbidden - rule-based accounts are not enabled for this platform.
- `404` — Customer or destination account not found
- `409` — Conflict - the `Idempotency-Key` was already used to create a different account, or the account for this key is still being provisioned. Retry with the same key.
- `500` — Internal service error

## Changes

- **2026-09-03** `50d71dfe03b8` — 1 info
  - endpoint added

[Change history](https://skmtc.dev/stainless-api/apis/grid-api/changes/internal-accounts/post.md)

---

[API](https://skmtc.dev/stainless-api/apis/grid-api.md) · [All operations](https://skmtc.dev/stainless-api/apis/grid-api/llms.txt) · [OpenAPI document](https://skmtc-service-production.skmtc.workers.dev/v1/apis/stainless-api/grid-api/revisions/50d71dfe03b8/schema)
