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

# Build a transaction

> Builds a `DEPOSIT` or a `REDEEM_REQUEST` for the vault `slug` names: it runs the checks below in order (the first failure answers), returns the unsigned transactions and simulates them. Nothing is signed or sent.

`DEPOSIT` (`syncDeposit`: the shares are minted in the same transaction):

- Checks: the amount is at least the minimum and within the per-request limit (400 `amount_below_minimum` / `invalid_amount`); `receiver`, when sent, equals `sender`, compared case-insensitively (400 on `body.receiver`); the vault exists (404 `vault_not_found`) and is active (409 `vault_not_active`); the vault is not paused (409 `vault_paused`); it accepts synchronous deposits and its NAV is valid (409 `deposits_unavailable`); the cap has room, counting the deposits waiting for settlement (409 `deposit_cap_reached`); the vault's allow list (`isAllowed`) accepts the sender and the receiver (403 `wallet_not_allowed`); the sender holds the amount (422 `insufficient_balance`); the simulation passes (422 `simulation_failed`).
- The transactions are an exact-amount `approve` of the deposit asset when the allowance is short, then `syncDeposit(amount, sender, referral)` on the vault: the shares go to the sender. `referral` defaults to the zero address.

`REDEEM_REQUEST`, a redeem request (`requestRedeem(shares, sender, sender)`: the shares leave the wallet at once, and the assets become claimable when the vault settles the request, usually within `window.maxDays`):

- Checks: the vault exists and is active (404 / 409); the vault is not paused (409 `vault_paused`); the vault's allow list accepts the sender (403 `wallet_not_allowed`); `shares` is at most the sender's balance (422 `insufficient_shares`); the sender has no redeem request waiting for settlement in this vault (409 `redeem_request_already_pending`); the simulation passes (422 `simulation_failed`).
- If the sender has a settled redeem request it has not claimed, `requestRedeem` pays those assets to the sender first, in the same transaction; `claimFirst` shows them (null otherwise). Once the new redeem request settles, the wallet claims its assets in the Kamui app, or its next redeem request pays them out.
- No approval is needed: the sender owns the shares.

Both types:

- `simulation.status` is `passed` (the bundle ran with `eth_simulateV1`, or a single transaction with `eth_call`), `partial` (the node cannot simulate a bundle and the deposit needs the approval first, so only the checks ran) or `skipped` (`skipSimulation: true`).
- A legacy slug resolves to its canonical vault, and the response carries the canonical slug.
- Transaction building must be enabled for your API client (403 `actions_not_enabled`) and can be switched off (503 `actions_disabled`). A `DEPOSIT`'s amount and receiver checks answer first.



## OpenAPI

````yaml api-reference/openapi.json POST /transaction.build
openapi: 3.1.0
info:
  title: Kamui External API
  description: >-
    API for Kamui vault data and for the unsigned transactions that deposit into
    a vault or create a redeem request on it, served by a Supabase Edge
    Function. The function never signs or sends a transaction: your users sign
    and send the transactions it builds. It writes no state apart from recording
    when each API key was last used.


    ## Base URL


    `https://api.kamui.finance/functions/v1/external-api`


    ## Requests


    - Call every action as `POST <base URL>/<action>` with a JSON object body
    and `Content-Type: application/json`. The body may be at most 16 KiB.

    - Bodies are strict: an unknown field is a 400, and so is a field named
    twice in one object (`is a duplicate field`).

    - Only POST is allowed. Any other method answers 405 `method_not_allowed`.

    - The function checks the method first, then the API key, then your rate
    limit, then the action. An unknown action counts against your read limit and
    answers 404 `route_not_found` with a valid key, and 401 without one.


    ## Authentication


    - Send your API key in the `x-partner-api-key` header on every request,
    including `health.ping`.

    - A key looks like `kmi_<id>_<secret>`: `kmi_`, 12 lowercase base32
    characters, `_`, then 43 base64url characters (60 characters in total).
    `kmi_<id>` is the key prefix. After creation Kamui sees only the prefix.

    - Kamui issues the keys. The full key is shown once, when it is created, so
    store it in a secret manager. A lost key cannot be recovered; Kamui rotates
    it instead.

    - Rotation issues a new key. The old key keeps working for a grace period
    that Kamui sets when it rotates (24 hours by default), then stops.

    - Kamui can also revoke a key at once.

    - A missing, malformed, unknown, revoked or expired key always answers the
    same 401 `unauthorized`.

    - Call the API from your backend only. The function sends no CORS headers,
    and a browser or mobile app must never hold the key.


    ## Request ids


    - You may send an `x-request-id` header: 1 to 128 letters, digits, `.`, `_`,
    `:` or `-`. Any other value is replaced with a new UUID.

    - Every response carries the id in its `x-request-id` header, and every
    error body in `requestId`. Quote it when you contact Kamui.


    ## Responses


    - Success: `{ "data": …, "asOf": <Unix seconds> }`.

    - Error: `{ "error": "<message>", "code": "<code>", "requestId": "<id>" }`,
    plus `details` (a list of `{ "path", "issue" }`) when the request is
    invalid. Branch on `code`; the message text may change.

    - Responses are never cached (`Cache-Control: no-store`).


    | HTTP | `code` | Meaning |

    | --- | --- | --- |

    | 400 | `invalid_request` | A field is missing, has the wrong type or value,
    or is unknown. See `details`. |

    | 400 | `invalid_amount` | The amount is above the per-request limit. See
    `details`. |

    | 400 | `amount_below_minimum` | The deposit is below the minimum. See
    `details`. |

    | 401 | `unauthorized` | The API key is missing, malformed, unknown, revoked
    or expired. |

    | 403 | `actions_not_enabled` | Transaction building is not enabled for your
    API client. Ask Kamui. |

    | 403 | `wallet_not_allowed` | The vault's allow list (`isAllowed`) does not
    accept the wallet. |

    | 404 | `route_not_found` | The action does not exist. |

    | 404 | `vault_not_found` | No vault has this slug. |

    | 405 | `method_not_allowed` | Use POST. |

    | 409 | `vault_not_active` | The vault exists but is not open yet. |

    | 409 | `vault_paused` | The vault is paused. |

    | 409 | `deposits_unavailable` | The vault does not accept synchronous
    deposits now (sync mode, or the NAV is being updated). |

    | 409 | `deposit_cap_reached` | The deposit would exceed the vault's cap. |

    | 409 | `redeem_request_already_pending` | The wallet already has a redeem
    request waiting for settlement in this vault. |

    | 413 | `payload_too_large` | The body is over 16 KiB. |

    | 415 | `unsupported_media_type` | Send `Content-Type: application/json`. |

    | 422 | `insufficient_balance` | The wallet holds less USDC than the
    deposit. |

    | 422 | `insufficient_shares` | The wallet holds fewer shares than the
    redeem request. |

    | 422 | `simulation_failed` | A built transaction reverts in simulation.
    `details` names the transaction and the error. |

    | 429 | `rate_limited` | Your client is over its per-minute limit. Wait
    `Retry-After` seconds. |

    | 500 | `internal_error` | Unexpected error. Retry later and quote the
    request id. |

    | 502 | `upstream_error` | A data source (the vault indexer or the chain)
    returned an error. Retry with backoff. |

    | 503 | `service_unavailable` | The service is temporarily unavailable.
    Retry with backoff. |

    | 503 | `actions_disabled` | Transaction building is switched off. The read
    actions still answer. |

    | 504 | `upstream_timeout` | A data source did not answer in time. Retry
    with backoff. |


    ## Data conventions


    - Onchain amounts are base-unit integer strings: USDC has 6 decimals, vault
    shares have 18.

    - In `vaults.history`, share prices and TVL are decimal strings in the
    deposit asset, with its decimals (`"1.002182"`).

    - APY and APR values are numbers in percent (`3.55` is 3.55% a year). Fees
    are in basis points (`100` is 1%).

    - USD values are numbers for display. USDC counts as exactly $1.

    - Timestamps are Unix seconds, UTC.

    - Addresses are accepted in lowercase or EIP-55 and returned in EIP-55.
    Other mixed case, all-uppercase hex and a `0X` prefix are a 400.

    - Vault slugs: `stable-vault`, `balanced-vault`, `boosted-vault`. The legacy
    slugs `advanced-vault` and `aggressive-vault` are accepted; responses always
    carry the canonical slug. Slugs are matched exactly: case and whitespace
    count, so `Stable-Vault` is a 400.

    - `users.transactions` cursors are opaque and signed. Send `nextCursor` back
    unchanged, with the same filters; a changed cursor is a 400
    `invalid_cursor`.

    - Ethereum mainnet only (`chainId` 1).


    ## Transactions


    `transaction.quote` and `transaction.build` cover two transaction types, set
    in the body's `type`:


    - `DEPOSIT`: a synchronous deposit of USDC (`syncDeposit`). The shares are
    minted in the same transaction.

    - `REDEEM_REQUEST`: a redeem request (`requestRedeem`). The shares leave the
    wallet at once, and the vault settles the request later. A redeem request is
    the only way out of a Kamui vault.


    Both take the vault's `slug` in the body, like every other action.


    - `transaction.quote` prices the transaction and says whether the vault
    takes it now (`availability`). It builds no transaction.

    - `transaction.build` runs every check in a fixed order (the first failure
    answers), returns the unsigned transactions and simulates them.

    - Send the transactions in `step` order from `from`, and wait for each
    receipt before you send the next. Each `to` is the vault or, for an
    approval, the deposit asset; `value` is always `"0"`. An approval is for the
    exact deposit amount, never unlimited.

    - Every read is pinned to `blockNumber`, and the simulation runs on top of
    it. Build again after a 409, or when more than 10 minutes have passed.

    - Once a redeem request settles, its assets are claimable. The API builds no
    claim: the wallet claims them in the Kamui app, or Lagoon pays them out in
    the wallet's next redeem request (`claimFirst`).

    - Transaction building must be enabled for your API client; until it is,
    both actions answer 403 `actions_not_enabled`.

    - Transaction building can be switched off. It then answers 503
    `actions_disabled`, and the read actions keep answering.


    ## Limits


    - Each client has per-minute request limits, shared by all of its API keys:
    one for the read actions and a lower one for the transaction-building
    actions. By default they are 120 read requests and 20 transaction requests a
    minute; Kamui can set other limits for your client.

    - Every request with a valid API key counts, whatever the answer: a 400, 413
    or 415 counts too, and an unknown action counts against the read limit. A
    request without a valid key (401) or with another method (405) does not
    count.

    - The transaction limit is checked before transaction building's own checks,
    so a 429 can come before a 403 `actions_not_enabled` or a 503
    `actions_disabled`.

    - The windows are fixed UTC minutes. Every counted response carries
    `RateLimit-Policy` (for example `"read";q=120;w=60`: the limit and the
    window in seconds), `RateLimit` (`"read";r=119;t=42`: the requests left and
    the seconds until the window resets), and `X-RateLimit-Limit`,
    `X-RateLimit-Remaining` and `X-RateLimit-Reset` (Unix seconds).

    - Over the limit, the API answers 429 `rate_limited` with `Retry-After` in
    seconds. Wait that long before the next request.

    - If Kamui cannot check the limit for a moment, the read actions still
    answer (without the rate-limit headers), and the transaction actions answer
    503 `service_unavailable`.

    - Avoid tight polling loops.
  version: 1.0.0
  contact:
    name: Kamui
    url: https://kamui.finance
servers:
  - url: '{baseUrl}'
    description: Kamui External API
    variables:
      baseUrl:
        default: https://api.kamui.finance/functions/v1/external-api
        description: >-
          The API base URL. It defaults to production; change it only if Kamui
          gave you another base URL.
security: []
tags:
  - name: Health
    description: Check that the API is up and that your key works.
  - name: Vaults
    description: Vault data that is the same for every wallet.
  - name: Users
    description: Data about one wallet.
  - name: Transactions
    description: >-
      Quotes and unsigned transactions that deposit into a vault or create a
      redeem request on it, and the checks behind them.
paths:
  /transaction.build:
    post:
      tags:
        - Transactions
      summary: Build a transaction
      description: >-
        Builds a `DEPOSIT` or a `REDEEM_REQUEST` for the vault `slug` names: it
        runs the checks below in order (the first failure answers), returns the
        unsigned transactions and simulates them. Nothing is signed or sent.


        `DEPOSIT` (`syncDeposit`: the shares are minted in the same
        transaction):


        - Checks: the amount is at least the minimum and within the per-request
        limit (400 `amount_below_minimum` / `invalid_amount`); `receiver`, when
        sent, equals `sender`, compared case-insensitively (400 on
        `body.receiver`); the vault exists (404 `vault_not_found`) and is active
        (409 `vault_not_active`); the vault is not paused (409 `vault_paused`);
        it accepts synchronous deposits and its NAV is valid (409
        `deposits_unavailable`); the cap has room, counting the deposits waiting
        for settlement (409 `deposit_cap_reached`); the vault's allow list
        (`isAllowed`) accepts the sender and the receiver (403
        `wallet_not_allowed`); the sender holds the amount (422
        `insufficient_balance`); the simulation passes (422
        `simulation_failed`).

        - The transactions are an exact-amount `approve` of the deposit asset
        when the allowance is short, then `syncDeposit(amount, sender,
        referral)` on the vault: the shares go to the sender. `referral`
        defaults to the zero address.


        `REDEEM_REQUEST`, a redeem request (`requestRedeem(shares, sender,
        sender)`: the shares leave the wallet at once, and the assets become
        claimable when the vault settles the request, usually within
        `window.maxDays`):


        - Checks: the vault exists and is active (404 / 409); the vault is not
        paused (409 `vault_paused`); the vault's allow list accepts the sender
        (403 `wallet_not_allowed`); `shares` is at most the sender's balance
        (422 `insufficient_shares`); the sender has no redeem request waiting
        for settlement in this vault (409 `redeem_request_already_pending`); the
        simulation passes (422 `simulation_failed`).

        - If the sender has a settled redeem request it has not claimed,
        `requestRedeem` pays those assets to the sender first, in the same
        transaction; `claimFirst` shows them (null otherwise). Once the new
        redeem request settles, the wallet claims its assets in the Kamui app,
        or its next redeem request pays them out.

        - No approval is needed: the sender owns the shares.


        Both types:


        - `simulation.status` is `passed` (the bundle ran with `eth_simulateV1`,
        or a single transaction with `eth_call`), `partial` (the node cannot
        simulate a bundle and the deposit needs the approval first, so only the
        checks ran) or `skipped` (`skipSimulation: true`).

        - A legacy slug resolves to its canonical vault, and the response
        carries the canonical slug.

        - Transaction building must be enabled for your API client (403
        `actions_not_enabled`) and can be switched off (503 `actions_disabled`).
        A `DEPOSIT`'s amount and receiver checks answer first.
      operationId: transaction_build
      parameters:
        - $ref: '#/components/parameters/RequestId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $schema: https://json-schema.org/draft/2020-12/schema
              oneOf:
                - type: object
                  properties:
                    type:
                      type: string
                      const: DEPOSIT
                      default: DEPOSIT
                    slug:
                      type: string
                      minLength: 1
                      maxLength: 64
                      pattern: ^[a-z0-9]+(?:-[a-z0-9]+)*$
                      description: >-
                        Vault slug, matched exactly: lowercase letters, digits
                        and single hyphens (`stable-vault`). Case and whitespace
                        count, so `Stable-Vault` and ` stable-vault` answer 400.
                        A legacy slug works; the response carries the canonical
                        one.
                      examples:
                        - stable-vault
                    amount:
                      type: string
                      minLength: 1
                      maxLength: 30
                      pattern: ^[1-9][0-9]{0,29}$
                      examples:
                        - '1000000000'
                    sender:
                      description: >-
                        Ethereum address: `0x` and 40 hex characters, in
                        lowercase or with a valid EIP-55 checksum. Other mixed
                        case, all-uppercase hex, a `0X` prefix and the zero
                        address answer 400.
                      type: string
                      minLength: 42
                      maxLength: 42
                      pattern: ^0x[0-9a-fA-F]{40}$
                      examples:
                        - '0x1111111111111111111111111111111111111111'
                    receiver:
                      description: >-
                        Ethereum address: `0x` and 40 hex characters, in
                        lowercase or with a valid EIP-55 checksum. Other mixed
                        case, all-uppercase hex, a `0X` prefix and the zero
                        address answer 400.
                      type: string
                      minLength: 42
                      maxLength: 42
                      pattern: ^0x[0-9a-fA-F]{40}$
                    referral:
                      description: >-
                        Ethereum address: `0x` and 40 hex characters, in
                        lowercase or with a valid EIP-55 checksum. Other mixed
                        case, all-uppercase hex and a `0X` prefix answer 400.
                      type: string
                      minLength: 42
                      maxLength: 42
                      pattern: ^0x[0-9a-fA-F]{40}$
                    chainId:
                      type: number
                      const: 1
                    skipSimulation:
                      type: boolean
                  required:
                    - type
                    - slug
                    - amount
                    - sender
                  additionalProperties: false
                  title: DEPOSIT
                - type: object
                  properties:
                    type:
                      type: string
                      const: REDEEM_REQUEST
                      default: REDEEM_REQUEST
                    slug:
                      type: string
                      minLength: 1
                      maxLength: 64
                      pattern: ^[a-z0-9]+(?:-[a-z0-9]+)*$
                      description: >-
                        Vault slug, matched exactly: lowercase letters, digits
                        and single hyphens (`stable-vault`). Case and whitespace
                        count, so `Stable-Vault` and ` stable-vault` answer 400.
                        A legacy slug works; the response carries the canonical
                        one.
                      examples:
                        - stable-vault
                    shares:
                      type: string
                      minLength: 1
                      maxLength: 30
                      pattern: ^[1-9][0-9]{0,29}$
                      examples:
                        - '250000000000000000000'
                    sender:
                      description: >-
                        Ethereum address: `0x` and 40 hex characters, in
                        lowercase or with a valid EIP-55 checksum. Other mixed
                        case, all-uppercase hex, a `0X` prefix and the zero
                        address answer 400.
                      type: string
                      minLength: 42
                      maxLength: 42
                      pattern: ^0x[0-9a-fA-F]{40}$
                      examples:
                        - '0x1111111111111111111111111111111111111111'
                    chainId:
                      type: number
                      const: 1
                    skipSimulation:
                      type: boolean
                  required:
                    - type
                    - slug
                    - shares
                    - sender
                  additionalProperties: false
                  title: REDEEM_REQUEST
            examples:
              deposit:
                summary: >-
                  Build a deposit of 1,000 USDC for a wallet (illustrative
                  address)
                value:
                  type: DEPOSIT
                  slug: stable-vault
                  amount: '1000000000'
                  sender: '0x1111111111111111111111111111111111111111'
              redeemRequest:
                summary: >-
                  Build a redeem request of 250 shares for a wallet
                  (illustrative address)
                value:
                  type: REDEEM_REQUEST
                  slug: stable-vault
                  shares: '250000000000000000000'
                  sender: '0x1111111111111111111111111111111111111111'
      responses:
        '200':
          description: Success
          headers:
            x-request-id:
              $ref: '#/components/headers/RequestId'
            ratelimit-policy:
              $ref: '#/components/headers/RateLimitPolicy'
            ratelimit:
              $ref: '#/components/headers/RateLimit'
            x-ratelimit-limit:
              $ref: '#/components/headers/XRateLimitLimit'
            x-ratelimit-remaining:
              $ref: '#/components/headers/XRateLimitRemaining'
            x-ratelimit-reset:
              $ref: '#/components/headers/XRateLimitReset'
          content:
            application/json:
              schema:
                $schema: https://json-schema.org/draft/2020-12/schema
                type: object
                properties:
                  data:
                    oneOf:
                      - type: object
                        properties:
                          type:
                            type: string
                            const: DEPOSIT
                          slug:
                            type: string
                          chainId:
                            type: number
                            const: 1
                          blockNumber:
                            type: integer
                            minimum: 0
                            maximum: 9007199254740991
                          vault:
                            type: object
                            properties:
                              address:
                                type: string
                              symbol:
                                type: string
                              shareDecimals:
                                type: integer
                                minimum: 0
                                maximum: 9007199254740991
                            required:
                              - address
                              - symbol
                              - shareDecimals
                            additionalProperties: false
                          depositAsset:
                            type: object
                            properties:
                              address:
                                type: string
                              symbol:
                                type: string
                              decimals:
                                type: integer
                                minimum: 0
                                maximum: 9007199254740991
                            required:
                              - address
                              - symbol
                              - decimals
                            additionalProperties: false
                          amount:
                            type: string
                            pattern: ^[0-9]{1,78}$
                          fees:
                            type: object
                            properties:
                              entryBps:
                                type: integer
                                minimum: 0
                                maximum: 9007199254740991
                            required:
                              - entryBps
                            additionalProperties: false
                          steps:
                            type: array
                            items:
                              type: string
                              enum:
                                - approve
                                - deposit
                          notes:
                            type: array
                            items:
                              type: string
                          sender:
                            type: string
                          receiver:
                            type: string
                          referral:
                            type: string
                          expectedShares:
                            type: string
                            pattern: ^[0-9]{1,78}$
                          transactions:
                            type: array
                            items:
                              type: object
                              properties:
                                step:
                                  type: integer
                                  exclusiveMinimum: 0
                                  maximum: 9007199254740991
                                label:
                                  type: string
                                  enum:
                                    - approve
                                    - deposit
                                    - redeem_request
                                description:
                                  type: string
                                chainId:
                                  type: number
                                  const: 1
                                from:
                                  type: string
                                to:
                                  type: string
                                data:
                                  type: string
                                  pattern: ^0x(?:[0-9a-fA-F]{2})*$
                                value:
                                  type: string
                                  const: '0'
                              required:
                                - step
                                - label
                                - description
                                - chainId
                                - from
                                - to
                                - data
                                - value
                              additionalProperties: false
                          simulation:
                            type: object
                            properties:
                              status:
                                type: string
                                enum:
                                  - passed
                                  - partial
                                  - skipped
                              method:
                                anyOf:
                                  - type: string
                                    enum:
                                      - eth_simulateV1
                                      - eth_call
                                  - type: 'null'
                              blockNumber:
                                type: integer
                                minimum: 0
                                maximum: 9007199254740991
                            required:
                              - status
                              - method
                              - blockNumber
                            additionalProperties: false
                        required:
                          - type
                          - slug
                          - chainId
                          - blockNumber
                          - vault
                          - depositAsset
                          - amount
                          - fees
                          - steps
                          - notes
                          - sender
                          - receiver
                          - referral
                          - expectedShares
                          - transactions
                          - simulation
                        additionalProperties: false
                        title: DEPOSIT
                      - type: object
                        properties:
                          type:
                            type: string
                            const: REDEEM_REQUEST
                          slug:
                            type: string
                          chainId:
                            type: number
                            const: 1
                          blockNumber:
                            type: integer
                            minimum: 0
                            maximum: 9007199254740991
                          vault:
                            type: object
                            properties:
                              address:
                                type: string
                              symbol:
                                type: string
                              shareDecimals:
                                type: integer
                                minimum: 0
                                maximum: 9007199254740991
                            required:
                              - address
                              - symbol
                              - shareDecimals
                            additionalProperties: false
                          depositAsset:
                            type: object
                            properties:
                              address:
                                type: string
                              symbol:
                                type: string
                              decimals:
                                type: integer
                                minimum: 0
                                maximum: 9007199254740991
                            required:
                              - address
                              - symbol
                              - decimals
                            additionalProperties: false
                          shares:
                            type: string
                            pattern: ^[0-9]{1,78}$
                          expectedAssets:
                            type: string
                            pattern: ^[0-9]{1,78}$
                          window:
                            type: object
                            properties:
                              maxDays:
                                type: integer
                                exclusiveMinimum: 0
                                maximum: 9007199254740991
                            required:
                              - maxDays
                            additionalProperties: false
                          fees:
                            type: object
                            properties:
                              exitBps:
                                type: integer
                                minimum: 0
                                maximum: 9007199254740991
                            required:
                              - exitBps
                            additionalProperties: false
                          claimFirst:
                            anyOf:
                              - type: object
                                properties:
                                  assets:
                                    type: string
                                    pattern: ^[0-9]{1,78}$
                                  shares:
                                    type: string
                                    pattern: ^[0-9]{1,78}$
                                required:
                                  - assets
                                  - shares
                                additionalProperties: false
                              - type: 'null'
                          steps:
                            type: array
                            items:
                              type: string
                              const: redeem_request
                          notes:
                            type: array
                            items:
                              type: string
                          sender:
                            type: string
                          transactions:
                            type: array
                            items:
                              type: object
                              properties:
                                step:
                                  type: integer
                                  exclusiveMinimum: 0
                                  maximum: 9007199254740991
                                label:
                                  type: string
                                  enum:
                                    - approve
                                    - deposit
                                    - redeem_request
                                description:
                                  type: string
                                chainId:
                                  type: number
                                  const: 1
                                from:
                                  type: string
                                to:
                                  type: string
                                data:
                                  type: string
                                  pattern: ^0x(?:[0-9a-fA-F]{2})*$
                                value:
                                  type: string
                                  const: '0'
                              required:
                                - step
                                - label
                                - description
                                - chainId
                                - from
                                - to
                                - data
                                - value
                              additionalProperties: false
                          simulation:
                            type: object
                            properties:
                              status:
                                type: string
                                enum:
                                  - passed
                                  - partial
                                  - skipped
                              method:
                                anyOf:
                                  - type: string
                                    enum:
                                      - eth_simulateV1
                                      - eth_call
                                  - type: 'null'
                              blockNumber:
                                type: integer
                                minimum: 0
                                maximum: 9007199254740991
                            required:
                              - status
                              - method
                              - blockNumber
                            additionalProperties: false
                        required:
                          - type
                          - slug
                          - chainId
                          - blockNumber
                          - vault
                          - depositAsset
                          - shares
                          - expectedAssets
                          - window
                          - fees
                          - claimFirst
                          - steps
                          - notes
                          - sender
                          - transactions
                          - simulation
                        additionalProperties: false
                        title: REDEEM_REQUEST
                  asOf:
                    type: integer
                    minimum: -9007199254740991
                    maximum: 9007199254740991
                required:
                  - data
                  - asOf
                additionalProperties: false
              examples:
                deposit:
                  summary: >-
                    DEPOSIT: an exact approval, then the deposit, simulated
                    together
                  value:
                    data:
                      type: DEPOSIT
                      slug: stable-vault
                      chainId: 1
                      blockNumber: 26147329
                      vault:
                        address: '0xcDA323c2DF692d989B24BA51D0aCCa924cf9a344'
                        symbol: USDst
                        shareDecimals: 18
                      depositAsset:
                        address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48'
                        symbol: USDC
                        decimals: 6
                      amount: '1000000000'
                      expectedShares: '997382077837769004220'
                      fees:
                        entryBps: 0
                      steps:
                        - approve
                        - deposit
                      notes:
                        - >-
                          Send the transactions in step order and wait for each
                          receipt before you send the next.
                        - >-
                          Shares are minted at the vault price when the deposit
                          executes; expectedShares uses the price at
                          blockNumber.
                        - >-
                          Build again after a 409, or when more than 10 minutes
                          have passed.
                      sender: '0x1111111111111111111111111111111111111111'
                      receiver: '0x1111111111111111111111111111111111111111'
                      referral: '0x0000000000000000000000000000000000000000'
                      transactions:
                        - step: 1
                          label: approve
                          description: >-
                            Approve the vault to transfer exactly the deposit
                            amount of the deposit asset.
                          chainId: 1
                          from: '0x1111111111111111111111111111111111111111'
                          to: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48'
                          data: >-
                            0x095ea7b3000000000000000000000000cda323c2df692d989b24ba51d0acca924cf9a344000000000000000000000000000000000000000000000000000000003b9aca00
                          value: '0'
                        - step: 2
                          label: deposit
                          description: >-
                            Deposit assets into the vault and receive vault
                            shares in the same transaction.
                          chainId: 1
                          from: '0x1111111111111111111111111111111111111111'
                          to: '0xcDA323c2DF692d989B24BA51D0aCCa924cf9a344'
                          data: >-
                            0xd01d073a000000000000000000000000000000000000000000000000000000003b9aca0000000000000000000000000011111111111111111111111111111111111111110000000000000000000000000000000000000000000000000000000000000000
                          value: '0'
                      simulation:
                        status: passed
                        method: eth_simulateV1
                        blockNumber: 26147329
                    asOf: 1791458270
                redeemRequest:
                  summary: 'REDEEM_REQUEST: one requestRedeem transaction'
                  value:
                    data:
                      type: REDEEM_REQUEST
                      slug: stable-vault
                      chainId: 1
                      blockNumber: 26147329
                      vault:
                        address: '0xcDA323c2DF692d989B24BA51D0aCCa924cf9a344'
                        symbol: USDst
                        shareDecimals: 18
                      depositAsset:
                        address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48'
                        symbol: USDC
                        decimals: 6
                      shares: '250000000000000000000'
                      expectedAssets: '250656198'
                      window:
                        maxDays: 1
                      fees:
                        exitBps: 0
                      claimFirst: null
                      steps:
                        - redeem_request
                      notes:
                        - >-
                          The final amount is fixed at the NAV used when the
                          redeem request settles.
                        - >-
                          After settlement the assets are claimable: the wallet
                          claims them in the Kamui app, or Lagoon pays them in
                          the wallet's next redeem request.
                        - >-
                          Build again after a 409, or when more than 10 minutes
                          have passed.
                      sender: '0x1111111111111111111111111111111111111111'
                      transactions:
                        - step: 1
                          label: redeem_request
                          description: >-
                            Create a redeem request for vault shares. The assets
                            become claimable after the vault settles the
                            request.
                          chainId: 1
                          from: '0x1111111111111111111111111111111111111111'
                          to: '0xcDA323c2DF692d989B24BA51D0aCCa924cf9a344'
                          data: >-
                            0x7d41c86e00000000000000000000000000000000000000000000000d8d726b7177a8000000000000000000000000000011111111111111111111111111111111111111110000000000000000000000001111111111111111111111111111111111111111
                          value: '0'
                      simulation:
                        status: passed
                        method: eth_simulateV1
                        blockNumber: 26147329
                    asOf: 1791458270
                redeemRequestPaysClaimable:
                  summary: >-
                    REDEEM_REQUEST while an earlier redeem request is claimable:
                    requestRedeem pays it out first
                  value:
                    data:
                      type: REDEEM_REQUEST
                      slug: stable-vault
                      chainId: 1
                      blockNumber: 26147329
                      vault:
                        address: '0xcDA323c2DF692d989B24BA51D0aCCa924cf9a344'
                        symbol: USDst
                        shareDecimals: 18
                      depositAsset:
                        address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48'
                        symbol: USDC
                        decimals: 6
                      shares: '250000000000000000000'
                      expectedAssets: '250656198'
                      window:
                        maxDays: 1
                      fees:
                        exitBps: 0
                      claimFirst:
                        assets: '250545500'
                        shares: '250000000000000000000'
                      steps:
                        - redeem_request
                      notes:
                        - >-
                          The final amount is fixed at the NAV used when the
                          redeem request settles.
                        - >-
                          After settlement the assets are claimable: the wallet
                          claims them in the Kamui app, or Lagoon pays them in
                          the wallet's next redeem request.
                        - >-
                          Build again after a 409, or when more than 10 minutes
                          have passed.
                        - >-
                          The sender has a settled redeem request to claim
                          (claimFirst): the requestRedeem transaction pays those
                          assets to the sender before it opens the new request.
                      sender: '0x1111111111111111111111111111111111111111'
                      transactions:
                        - step: 1
                          label: redeem_request
                          description: >-
                            Create a redeem request for vault shares. The assets
                            become claimable after the vault settles the
                            request.
                          chainId: 1
                          from: '0x1111111111111111111111111111111111111111'
                          to: '0xcDA323c2DF692d989B24BA51D0aCCa924cf9a344'
                          data: >-
                            0x7d41c86e00000000000000000000000000000000000000000000000d8d726b7177a8000000000000000000000000000011111111111111111111111111111111111111110000000000000000000000001111111111111111111111111111111111111111
                          value: '0'
                      simulation:
                        status: passed
                        method: eth_simulateV1
                        blockNumber: 26147329
                    asOf: 1791458270
        '400':
          description: The request is not valid. `details` names each failing field.
          headers:
            x-request-id:
              $ref: '#/components/headers/RequestId'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ExternalApiError'
              examples:
                missingSender:
                  summary: No sender
                  value:
                    error: The request is not valid. See details.
                    code: invalid_request
                    requestId: 54b94174-0f08-4598-bae6-23beb4699e87
                    details:
                      - path: body.sender
                        issue: 'Invalid input: expected string, received undefined'
                receiverNotSender:
                  summary: A receiver other than the sender
                  value:
                    error: The request is not valid. See details.
                    code: invalid_request
                    requestId: da068048-1cf7-4506-9963-eb1943d65fa7
                    details:
                      - path: body.receiver
                        issue: must equal sender
                missingShares:
                  summary: A REDEEM_REQUEST without shares
                  value:
                    error: The request is not valid. See details.
                    code: invalid_request
                    requestId: 50c85c8d-d9ea-4bde-a701-d24ca0581944
                    details:
                      - path: body.shares
                        issue: 'Invalid input: expected string, received undefined'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/ActionForbidden'
        '404':
          $ref: '#/components/responses/VaultNotFound'
        '409':
          $ref: '#/components/responses/TransactionConflict'
        '413':
          $ref: '#/components/responses/PayloadTooLarge'
        '415':
          $ref: '#/components/responses/UnsupportedMediaType'
        '422':
          $ref: '#/components/responses/TransactionUnprocessable'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'
        '502':
          $ref: '#/components/responses/UpstreamError'
        '503':
          $ref: '#/components/responses/ActionsUnavailable'
        '504':
          $ref: '#/components/responses/UpstreamTimeout'
        default:
          description: Error
          content:
            application/json:
              schema:
                $schema: https://json-schema.org/draft/2020-12/schema
                type: object
                properties:
                  error:
                    type: string
                  code:
                    type: string
                    enum:
                      - invalid_request
                      - invalid_address
                      - invalid_amount
                      - amount_below_minimum
                      - invalid_cursor
                      - unsupported_chain
                      - wallet_not_allowed
                      - vault_not_found
                      - route_not_found
                      - method_not_allowed
                      - vault_not_active
                      - vault_paused
                      - deposits_unavailable
                      - deposit_cap_reached
                      - redeem_request_already_pending
                      - payload_too_large
                      - unsupported_media_type
                      - insufficient_balance
                      - insufficient_shares
                      - simulation_failed
                      - rate_limited
                      - jurisdiction_restricted
                      - internal_error
                      - upstream_error
                      - service_unavailable
                      - actions_disabled
                      - history_unavailable
                      - upstream_timeout
                      - unauthorized
                      - actions_not_enabled
                  requestId:
                    type: string
                  details:
                    maxItems: 10
                    type: array
                    items:
                      type: object
                      properties:
                        path:
                          type: string
                          maxLength: 128
                        issue:
                          type: string
                          maxLength: 200
                      required:
                        - path
                        - issue
                      additionalProperties: false
                required:
                  - error
                  - code
                  - requestId
                additionalProperties: false
      security:
        - partnerApiKey: []
components:
  parameters:
    RequestId:
      name: x-request-id
      in: header
      required: false
      description: >-
        Your id for this request: 1 to 128 letters, digits, `.`, `_`, `:` or
        `-`. It is echoed in the response. Any other value is replaced with a
        new UUID.
      schema:
        type: string
        pattern: ^[A-Za-z0-9._:-]{1,128}$
  headers:
    RequestId:
      description: >-
        The request id: yours when it was valid, otherwise a new UUID. Quote it
        when you contact Kamui.
      schema:
        type: string
    RateLimitPolicy:
      description: >-
        Your client's limit for this kind of action, as an IETF RateLimit-Policy
        field: `"read";q=120;w=60` is 120 requests per 60-second window.
        `"actions"` is the transaction-building actions.
      schema:
        type: string
    RateLimit:
      description: >-
        The current window, as an IETF RateLimit field: `"read";r=119;t=42` is
        119 requests left and 42 seconds until the window resets.
      schema:
        type: string
    XRateLimitLimit:
      description: Requests allowed in the current window.
      schema:
        type: integer
    XRateLimitRemaining:
      description: Requests left in the current window.
      schema:
        type: integer
    XRateLimitReset:
      description: When the current window resets, in Unix seconds.
      schema:
        type: integer
    RetryAfter:
      description: Seconds to wait before the next request.
      schema:
        type: integer
  schemas:
    ExternalApiError:
      $schema: https://json-schema.org/draft/2020-12/schema
      type: object
      properties:
        error:
          type: string
        code:
          type: string
          enum:
            - invalid_request
            - invalid_address
            - invalid_amount
            - amount_below_minimum
            - invalid_cursor
            - unsupported_chain
            - wallet_not_allowed
            - vault_not_found
            - route_not_found
            - method_not_allowed
            - vault_not_active
            - vault_paused
            - deposits_unavailable
            - deposit_cap_reached
            - redeem_request_already_pending
            - payload_too_large
            - unsupported_media_type
            - insufficient_balance
            - insufficient_shares
            - simulation_failed
            - rate_limited
            - jurisdiction_restricted
            - internal_error
            - upstream_error
            - service_unavailable
            - actions_disabled
            - history_unavailable
            - upstream_timeout
            - unauthorized
            - actions_not_enabled
        requestId:
          type: string
        details:
          maxItems: 10
          type: array
          items:
            type: object
            properties:
              path:
                type: string
                maxLength: 128
              issue:
                type: string
                maxLength: 200
            required:
              - path
              - issue
            additionalProperties: false
      required:
        - error
        - code
        - requestId
      additionalProperties: false
  responses:
    Unauthorized:
      description: The API key is missing, malformed, unknown, revoked or expired.
      headers:
        x-request-id:
          $ref: '#/components/headers/RequestId'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ExternalApiError'
          examples:
            unauthorized:
              summary: The API key is missing, malformed, unknown, revoked or expired.
              value:
                error: Unauthorized.
                code: unauthorized
                requestId: ea80702c-a332-4e32-922e-76bcb02e6156
    ActionForbidden:
      description: >-
        The vault's allow list (`isAllowed`) does not accept the wallet. Or
        transaction building is not enabled for your API client.
      headers:
        x-request-id:
          $ref: '#/components/headers/RequestId'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ExternalApiError'
          examples:
            wallet_not_allowed:
              summary: >-
                The vault's allow list (`isAllowed`) does not accept the wallet.
                Or transaction building is not enabled for your API client.
              value:
                error: This wallet is not allowed to use this vault.
                code: wallet_not_allowed
                requestId: f380ff7f-af51-432a-9691-36bbc1b6903d
            actions_not_enabled:
              summary: >-
                Transaction building is not enabled for your API client. Ask
                Kamui.
              value:
                error: >-
                  Transaction building is not enabled for this API client.
                  Contact Kamui.
                code: actions_not_enabled
                requestId: 01dc27cb-8bde-4711-8e2b-5417febec986
    VaultNotFound:
      description: No vault has this slug.
      headers:
        x-request-id:
          $ref: '#/components/headers/RequestId'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ExternalApiError'
          examples:
            vault_not_found:
              summary: No vault has this slug.
              value:
                error: No vault exists with this slug.
                code: vault_not_found
                requestId: 3e515e1a-ad93-4506-81fc-aa47575c15f6
    TransactionConflict:
      description: >-
        The vault cannot take this transaction now: it is not active yet or is
        paused; for a DEPOSIT, it does not accept synchronous deposits (sync
        mode, or the NAV is being updated) or the deposit would exceed its cap;
        for a REDEEM_REQUEST, the sender already has a redeem request waiting
        for settlement. Build again later.
      headers:
        x-request-id:
          $ref: '#/components/headers/RequestId'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ExternalApiError'
          examples:
            vault_paused:
              summary: >-
                The vault cannot take this transaction now: it is not active yet
                or is paused; for a DEPOSIT, it does not accept synchronous
                deposits (sync mode, or the NAV is being updated) or the deposit
                would exceed its cap; for a REDEEM_REQUEST, the sender already
                has a redeem request waiting for settlement. Build again later.
              value:
                error: Deposits and redeem requests are paused for this vault.
                code: vault_paused
                requestId: f196a4b2-8340-4fd3-ae58-f7b5dbda7106
            vault_not_active:
              summary: The vault exists but is not open yet.
              value:
                error: This vault is not open yet.
                code: vault_not_active
                requestId: cf436109-bd86-45a5-93b6-c0d8a691768e
            deposits_unavailable:
              summary: The vault does not accept synchronous deposits now.
              value:
                error: >-
                  Deposits are temporarily unavailable for this vault. Try again
                  later.
                code: deposits_unavailable
                requestId: 5281edf8-46e8-4c60-8c7f-3db3f5cb5c20
            deposit_cap_reached:
              summary: The deposit would exceed the vault's cap.
              value:
                error: This deposit would exceed the vault capacity.
                code: deposit_cap_reached
                requestId: 849ab219-22d6-46df-b658-c34d63bd6082
            redeem_request_already_pending:
              summary: >-
                The sender already has a redeem request waiting for settlement
                in this vault.
              value:
                error: >-
                  This wallet already has a pending redeem request for this
                  vault.
                code: redeem_request_already_pending
                requestId: 08512f3a-a739-40df-822c-82e773f176aa
    PayloadTooLarge:
      description: The body is over 16 KiB.
      headers:
        x-request-id:
          $ref: '#/components/headers/RequestId'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ExternalApiError'
          examples:
            payload_too_large:
              summary: The body is over 16 KiB.
              value:
                error: The request body is too large.
                code: payload_too_large
                requestId: 0c8e5a7d-3f21-4b96-a4d8-7e1b9c2f6a30
    UnsupportedMediaType:
      description: The body was not sent as application/json.
      headers:
        x-request-id:
          $ref: '#/components/headers/RequestId'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ExternalApiError'
          examples:
            unsupported_media_type:
              summary: The body was not sent as application/json.
              value:
                error: Send the request body as application/json.
                code: unsupported_media_type
                requestId: 9b4f6e2a-1c7d-4a85-8e3f-5d0a2b6c9e17
    TransactionUnprocessable:
      description: >-
        The sender holds less USDC than the deposit or fewer shares than the
        redeem request, or a built transaction reverts in simulation.
      headers:
        x-request-id:
          $ref: '#/components/headers/RequestId'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ExternalApiError'
          examples:
            insufficient_balance:
              summary: >-
                The sender holds less USDC than the deposit or fewer shares than
                the redeem request, or a built transaction reverts in
                simulation.
              value:
                error: The wallet balance is lower than the amount.
                code: insufficient_balance
                requestId: 812765a5-46fa-4fee-8f07-82cfeabc46cf
            insufficient_shares:
              summary: The sender holds fewer shares than the redeem request.
              value:
                error: The wallet holds fewer shares than requested.
                code: insufficient_shares
                requestId: 16f03ad6-c2c5-4cfb-a408-e1eb8e063a24
            simulation_failed:
              summary: A built transaction reverts in simulation.
              value:
                error: The transaction would fail onchain. See details.
                code: simulation_failed
                requestId: 4daebf0a-dae7-4ec2-a17d-2c2d6d8cff74
                details:
                  - path: transactions.1
                    issue: >-
                      step 2 (deposit) reverts: EnforcedPause (selector
                      0xd93c0665)
    RateLimited:
      description: >-
        Your client is over its per-minute limit for this kind of action. Wait
        `Retry-After` seconds before the next request.
      headers:
        x-request-id:
          $ref: '#/components/headers/RequestId'
        retry-after:
          $ref: '#/components/headers/RetryAfter'
        ratelimit-policy:
          $ref: '#/components/headers/RateLimitPolicy'
        ratelimit:
          $ref: '#/components/headers/RateLimit'
        x-ratelimit-limit:
          $ref: '#/components/headers/XRateLimitLimit'
        x-ratelimit-remaining:
          $ref: '#/components/headers/XRateLimitRemaining'
        x-ratelimit-reset:
          $ref: '#/components/headers/XRateLimitReset'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ExternalApiError'
          examples:
            rate_limited:
              summary: >-
                Your client is over its per-minute limit for this kind of
                action. Wait `Retry-After` seconds before the next request.
              value:
                error: Too many requests. Wait and try again.
                code: rate_limited
                requestId: 8e2f4a6c-1b3d-4e5f-9a7b-0c2d4e6f8a1b
    InternalError:
      description: Unexpected error. Retry later and quote the request id.
      headers:
        x-request-id:
          $ref: '#/components/headers/RequestId'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ExternalApiError'
          examples:
            internal_error:
              summary: Unexpected error. Retry later and quote the request id.
              value:
                error: An unexpected error occurred.
                code: internal_error
                requestId: 4a7c9e1f-6b2d-4f83-9c05-8e3a1d7b2f64
    UpstreamError:
      description: >-
        A data source (the vault indexer or the chain) returned an error. Retry
        with backoff.
      headers:
        x-request-id:
          $ref: '#/components/headers/RequestId'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ExternalApiError'
          examples:
            upstream_error:
              summary: >-
                A data source (the vault indexer or the chain) returned an
                error. Retry with backoff.
              value:
                error: An upstream data source returned an error.
                code: upstream_error
                requestId: 2e6b8d4f-9a13-4c57-b8e2-1f7c3a5d9b06
    ActionsUnavailable:
      description: >-
        Transaction building is switched off (the read actions still answer), or
        the service is temporarily unavailable. Retry later.
      headers:
        x-request-id:
          $ref: '#/components/headers/RequestId'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ExternalApiError'
          examples:
            actions_disabled:
              summary: >-
                Transaction building is switched off (the read actions still
                answer), or the service is temporarily unavailable. Retry later.
              value:
                error: Transaction building is temporarily disabled.
                code: actions_disabled
                requestId: b77ae8f8-85c9-4ddd-a43d-10bbad4c5526
            service_unavailable:
              summary: The service is temporarily unavailable. Retry with backoff.
              value:
                error: The service is temporarily unavailable.
                code: service_unavailable
                requestId: e8519b78-574e-448f-99ba-b2e44ea6b8b1
    UpstreamTimeout:
      description: A data source did not answer in time. Retry with backoff.
      headers:
        x-request-id:
          $ref: '#/components/headers/RequestId'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ExternalApiError'
          examples:
            upstream_timeout:
              summary: A data source did not answer in time. Retry with backoff.
              value:
                error: An upstream data source did not respond in time.
                code: upstream_timeout
                requestId: 5c9e3b7a-2d64-4f18-b7a9-3e1d8c6f2b40
  securitySchemes:
    partnerApiKey:
      type: apiKey
      in: header
      name: x-partner-api-key
      description: >-
        The client's own API key (`kmi_<id>_<secret>`), issued by Kamui. A
        missing, malformed, unknown, revoked or expired key answers 401
        unauthorized.

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.