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

# Update a virtual account

> Change the `markup` or the `metadata` of one of your virtual accounts. **Only what you send changes** — every field you leave out keeps its value.

A new markup prices the deposits that settle after the call. A deposit that has already settled keeps the markup it settled with. Payouts are not affected: each payout carries its own `client_markup`.

The response is the whole account, in the same shape [Get a virtual account](/api-reference/virtual-accounts/get-a-virtual-account) returns.



## OpenAPI

````yaml /openapi/kira-api.2026-06-01.json patch /v1/virtual-accounts/{virtual_account_id}
openapi: 3.1.0
info:
  title: Kira API
  version: '2026-06-01'
  description: >-
    REST API for users, KYC/KYB verification, virtual accounts, payouts,
    recipients, and webhooks. Every request requires an `x-api-key` header and a
    bearer access token (see Authentication). Pin your account to version
    `2026-04-14` before integrating.
  contact:
    name: Kira API Support
    email: support@kirafin.ai
servers:
  - url: https://api.balampay.com
    description: Production
  - url: https://api.balampay.com/sandbox
    description: Sandbox
security:
  - bearerAuth: []
    apiKeyAuth: []
tags:
  - name: Authentication
  - name: Versioning
  - name: Users
  - name: Virtual Accounts
  - name: Recipients
  - name: Quotations
  - name: Payouts
  - name: Reference
  - name: RFIs
paths:
  /v1/virtual-accounts/{virtual_account_id}:
    patch:
      tags:
        - Virtual Accounts
      summary: Update a virtual account
      description: >-
        Change the `markup` or the `metadata` of one of your virtual accounts.
        **Only what you send changes** — every field you leave out keeps its
        value.


        A new markup prices the deposits that settle after the call. A deposit
        that has already settled keeps the markup it settled with. Payouts are
        not affected: each payout carries its own `client_markup`.


        The response is the whole account, in the same shape [Get a virtual
        account](/api-reference/virtual-accounts/get-a-virtual-account) returns.
      operationId: patch_v1-virtual-accounts-virtual-account-id
      parameters:
        - in: path
          name: virtual_account_id
          required: true
          schema:
            type: string
            format: uuid
          description: UUID of the account to change.
        - in: header
          name: X-Api-Version
          required: false
          description: >-
            Version applied to this request. It wins over your account's pinned
            version — see [Versioning](/using-the-api/versioning).
          schema:
            type: string
            example: '2026-06-01'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateVirtualAccountRequest'
            examples:
              change-markup:
                summary: Change one fee, remove another
                value:
                  markup:
                    wire_fixed_fee: '2.00'
                    inbound_variable_fee_pct: null
              change-metadata:
                summary: Set one key, delete another
                value:
                  metadata:
                    order_id: A-17
                    old_ref: ''
      responses:
        '200':
          description: Success.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/VirtualAccountDetail'
              example:
                id: 11111111-2222-3333-4444-555555555555
                user_id: aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee
                status: active
                type: US_BANK
                bank: austin_capital_trust
                mode: fiat
                destination: null
                source_deposit_instructions:
                  currency: usd
                  bank_name: Example Bank National Association
                  bank_address: 1 Second Street South, St. Cloud, MN, 56301
                  bank_account_number: '1000000001'
                  bank_routing_number: '000000001'
                  bank_beneficiary_name: Northwind Trading LLC
                  bank_beneficiary_address: 1 Market Street, San Francisco, CA, 94105
                payment_methods:
                  inbound:
                    - name: WIRE
                      status: active
                    - name: ACH
                      status: active
                  outbound:
                    - name: WIRE
                      status: active
                    - name: ACH
                      status: active
                methods:
                  inbound:
                    - name: WIRE
                      status: active
                    - name: ACH
                      status: active
                  outbound:
                    - name: WIRE
                      status: active
                    - name: ACH
                      status: active
                account_holder_name: Northwind Trading LLC
                account_number: '1000000001'
                routing_number: '000000001'
                bank_name: Example Bank National Association
                bank_address: 1 Second Street South, St. Cloud, MN, 56301
                account_holder_address: 1 Market Street, San Francisco, CA, 94105
                description: Operating account
                markup:
                  wire_fixed_fee: '2.00'
                  ach_fixed_fee: '0.50'
                created_at: '2026-09-01T12:00:00.000Z'
                updated_at: '2026-09-02T09:30:00.000Z'
                metadata: {}
        '400':
          description: >-
            Nothing changed. Read `code` first: `validation_error` means the
            body does not meet a rule, and `details` names each field. A body
            without `code` means the account id is not a UUID, or the metadata
            would pass a limit once merged.
          content:
            application/json:
              examples:
                body-rule:
                  summary: A value breaks a rule
                  value:
                    code: validation_error
                    error: Invalid data
                    details:
                      - message: >-
                          markup.inbound_variable_fee_pct is Must be at most
                          2.00
                empty-body:
                  summary: Nothing to change
                  value:
                    code: validation_error
                    error: Invalid data
                    details:
                      - message: ' is PATCH body must contain at least one mutable field'
                metadata-after-merge:
                  summary: Metadata over 50 keys once merged
                  value:
                    statusCode: 400
                    error: Bad Request
                    message: >-
                      Invalid metadata: metadata supports at most 50 keys per
                      resource
                    timestamp: '2026-09-01T12:00:00.000Z'
                malformed-id:
                  summary: The account id is not a UUID
                  value:
                    error: Invalid request data
                    details:
                      - path: id
                        message: Invalid virtual account ID format
                        code: invalid_string
        '403':
          description: >-
            Your request was turned away before it reached the API. The message
            talks about routing, but any of these causes it:


            - The `x-api-key` header is missing or wrong.

            - Your bearer token has expired. Get a new one from [Get access
            token](/api-reference/authentication/get-access-token).

            - The path or the HTTP method does not match. In sandbox, check that
            the path sits under the `/sandbox` prefix.


            A missing `Authorization` header comes back as a `401` with the same
            body.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                code: invalid_request
                message: >-
                  The request could not be matched to a valid route, or was
                  malformed. Verify the path and HTTP method against the API
                  reference. This is a routing or request error, not a
                  credentials or signature problem.
        '404':
          description: >-
            No account of yours has that id. The same body comes back whether
            the id does not exist or the account belongs to another account
            holder, so it never reveals which.
          content:
            application/json:
              schema:
                type: object
                properties:
                  statusCode:
                    type: integer
                    description: Repeats the HTTP status.
                  error:
                    type: string
                    description: Always `Not Found`.
                  message:
                    type: string
                    description: Names the id that was not found.
                  timestamp:
                    type: string
                    description: When the call was rejected, as an ISO 8601 timestamp.
              example:
                statusCode: 404
                error: Not Found
                message: Virtual account 11111111-2222-3333-4444-555555555555 not found
                timestamp: '2026-09-01T12:00:00.000Z'
      security:
        - bearerAuth: []
          apiKeyAuth: []
      servers:
        - url: https://api.balampay.com/sandbox
          description: Sandbox
        - url: https://api.balampay.com
          description: Production
components:
  schemas:
    UpdateVirtualAccountRequest:
      type: object
      description: Send `markup`, `metadata`, or both.
      properties:
        markup:
          type: object
          description: >-
            The fees to change on this account, each a decimal string with at
            most two decimals. A value sets that fee, `null` removes it, and a
            fee you leave out keeps its value. Any key not listed here is
            rejected, and so is an empty object.
          minProperties: 1
          properties:
            wire_fixed_fee:
              type:
                - string
                - 'null'
              pattern: ^\d+(\.\d{1,2})?$
              description: Flat fee on an inbound wire. In USD. At most `"50.00"`.
            ach_fixed_fee:
              type:
                - string
                - 'null'
              pattern: ^\d+(\.\d{1,2})?$
              description: Flat fee on an inbound ACH transfer. In USD. At most `"50.00"`.
            inbound_variable_fee_pct:
              type:
                - string
                - 'null'
              pattern: ^\d+(\.\d{1,2})?$
              description: >-
                Percentage fee on an inbound deposit. A percentage: `"0.50"` is
                0.50%. At most `"2.00"`.
            usd_usdc_conversion_fee_pct:
              type:
                - string
                - 'null'
              pattern: ^\d+(\.\d{1,2})?$
              description: >-
                Percentage fee on converting USD to a token. A percentage:
                `"0.50"` is 0.50%. At most `"2.00"`.
          additionalProperties: false
        metadata:
          type: object
          additionalProperties:
            type: string
          description: >-
            A patch, not a replacement: a key with a value sets it, a key with
            `""` deletes it, and `{}` clears every key. The limits apply to the
            result — see [Metadata](/reference/metadata).
      minProperties: 1
    VirtualAccountDetail:
      type: object
      description: >-
        One virtual account. The six flat bank fields repeat what
        `source_deposit_instructions` holds: absent when it is `null`, and
        `null` where it holds an empty value.
      properties:
        id:
          type: string
          format: uuid
          description: Virtual account UUID.
        user_id:
          type: string
          format: uuid
          description: UUID of the user that owns the account.
        status:
          type: string
          description: >-
            Where the account is in its lifecycle — see [Virtual account
            values](/reference/virtual-accounts/values#status). Available
            options: `pending`, `activating`, `active`, `failed`, `deactivated`.
        type:
          type: string
          enum:
            - US_BANK
          description: Account type.
        bank:
          type:
            - string
            - 'null'
          description: >-
            Which bank the account runs on, and with it the rail — see [Virtual
            account values](/reference/virtual-accounts/values#bank). `null`
            while the bank is still opening it.
        mode:
          type: string
          description: >-
            What the account does with a deposit. Available options: `fiat`,
            `crypto`. See [Virtual account
            values](/reference/virtual-accounts/values#mode).
        destination:
          type:
            - object
            - 'null'
          description: >-
            Where a `crypto`-mode deposit is sent. `null` on a `fiat`-mode
            account.
          properties:
            currency:
              type: string
              description: >-
                Token the deposit is converted to. Available options: `USDC`,
                `USDT`. See [Virtual account
                values](/reference/virtual-accounts/values#destination-currency).
            network:
              type: string
              description: >-
                Chain the token is sent on. Available options: `polygon`,
                `solana`, `tron`. See [Virtual account
                values](/reference/virtual-accounts/values#destination-network).
            address:
              type: string
              description: Wallet address the token is sent to.
        source_deposit_instructions:
          type:
            - object
            - 'null'
          description: >-
            The bank details a payer uses to send money to this account. `null`
            until the bank assigns them.


            They can also arrive filled with placeholders, such as an
            `account_number` of `PENDING-ACT-ACCOUNT`. Treat them as real only
            after the `virtual_account.activated` webhook — see
            [Webhooks](/webhooks/overview).
          properties:
            currency:
              type: string
              description: Currency the account takes. Always `usd`.
            bank_name:
              type: string
              description: Name of the bank holding the account.
            bank_address:
              type: string
              description: Postal address of that bank.
            bank_account_number:
              type: string
              description: Account number the payer sends to.
            bank_routing_number:
              type: string
              description: Routing number the payer sends to.
            bank_beneficiary_name:
              type: string
              description: Name the payment must be made out to.
            bank_beneficiary_address:
              type: string
              description: Postal address of that beneficiary.
        payment_methods:
          type:
            - object
            - 'null'
          description: Which rails the account takes money on and pays out on.
          properties:
            inbound:
              type:
                - array
                - 'null'
              items:
                $ref: '#/components/schemas/PaymentMethod'
              description: Rails you can receive a deposit on, such as `WIRE` or `ACH`.
            outbound:
              type:
                - array
                - 'null'
              items:
                $ref: '#/components/schemas/PaymentMethod'
              description: Rails you can pay out on.
        methods:
          type:
            - object
            - 'null'
          description: The same value as `payment_methods`.
          properties:
            inbound:
              type:
                - array
                - 'null'
              items:
                $ref: '#/components/schemas/PaymentMethod'
              description: The same value as `payment_methods.inbound`.
            outbound:
              type:
                - array
                - 'null'
              items:
                $ref: '#/components/schemas/PaymentMethod'
              description: The same value as `payment_methods.outbound`.
        account_holder_name:
          type:
            - string
            - 'null'
          description: Name the payment must be made out to.
        account_number:
          type:
            - string
            - 'null'
          description: Account number the payer sends to.
        routing_number:
          type:
            - string
            - 'null'
          description: Routing number the payer sends to.
        bank_name:
          type:
            - string
            - 'null'
          description: Name of the bank holding the account.
        bank_address:
          type:
            - string
            - 'null'
          description: Postal address of that bank.
        account_holder_address:
          type:
            - string
            - 'null'
          description: Postal address of the beneficiary.
        description:
          type: string
          description: >-
            Label you set when you created the account. Absent when you set
            none.
        status_reason:
          type: string
          description: >-
            Why the account is in its current status, in the bank's own words.
            Free text — read it, do not parse it. Absent when there is nothing
            to report.
        markup:
          type: object
          description: >-
            Your fees on this account, each a decimal string. Absent when none
            are set.
          properties:
            wire_fixed_fee:
              type: string
              description: Flat fee on an inbound wire.
            ach_fixed_fee:
              type: string
              description: Flat fee on an inbound ACH transfer.
            inbound_variable_fee_pct:
              type: string
              description: Percentage fee on an inbound deposit.
            usd_usdc_conversion_fee_pct:
              type: string
              description: Percentage fee on converting USD to a token.
        created_at:
          type: string
          description: When the account was created, as an ISO 8601 timestamp.
        updated_at:
          type: string
          description: When the account last changed, as an ISO 8601 timestamp.
        metadata:
          type: object
          description: >-
            Key/value pairs you attached to the account. `{}` when you attached
            none.
          additionalProperties: true
    ErrorResponse:
      type: object
      properties:
        message:
          type: string
        code:
          type: string
        statusCode:
          type: number
        error:
          type: string
        timestamp:
          type: string
        path:
          type: string
        details: {}
      required:
        - message
    PaymentMethod:
      type: object
      description: One rail on a virtual account.
      properties:
        name:
          type: string
          description: Rail name, such as `WIRE` or `ACH`.
        status:
          type: string
          description: >-
            Whether the rail can be used right now.


            Available options: `active`, `disabled`. See [Virtual account
            values](/reference/virtual-accounts/values#payment_methods-status).
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: >-
        The `data.access_token` value from [Get access
        token](/api-reference/authentication/get-access-token).
    apiKeyAuth:
      type: apiKey
      in: header
      name: x-api-key
      description: API key issued by Kira.

````