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

# Record a deposit a user just sent

> Records a deposit by its source tx, with the account it is for (whose receivers are registered with it). The tx is read on its chain first: `422` when it made no bridge deposit or reverted, when the deposit's receiver is not the account's NEAR Intents receiver, or when the chain is one this service cannot read (Solana, TRON). A deposit read on chain is kept with its fields (`nonce`, `token`, `amount`, `receiver`) and the account its receiver is; a tx the chain does not show yet is kept as a claim and checked again later (dropped if it never shows). The row is unique on `(chain_id, tx)`. Nothing is credited: call `POST /relay/deposit` for that.



## OpenAPI

````yaml https://mpc.hex-api.app/openapi.json post /bridge/deposits
openapi: 3.1.0
info:
  title: HEX MPC API
  version: 1.0.0
  summary: HOT bridge signatures and relay, the bridge registry and monitor.
  description: >
    The public API of `hex-mpc`, a Cloudflare Worker in front of the HOT MPC
    nodes. It replaces the old HOT backend's bridge endpoints

    (`api0.herewallet.app`: `process_bridge_deposit`, `auto_deposit_register`,
    ...) and HOR (`rpc1.hotdao.ai`, `rpc2.hotdao.ai`).


    ## Which routes to use


    - **Credit a deposit to NEAR Intents**: `POST /relay/deposit` with the
    source tx (or the deposit's fields). The service reads the deposit on its
    chain, signs it and sends `mt_deposit_call` on NEAR, paying the gas. This is
    what `process_bridge_deposit` did.

    - **Pay out withdrawals**: `POST /relay/withdraw` with the chain and the
    receiver; poll `GET /relay/jobs/{chain}/{id}`.

    - **Clear a paid withdrawal**: `POST /relay/clear`.

    - **Submit transactions yourself**: the `Signatures` routes return the MPC
    signatures only.

    - **Record what your users do** (optional, for support and recovery): `POST
    /bridge/register`, `/bridge/deposits`, `/bridge/withdrawals`.


    Every relay call sends only what holds on chain (a deposit that happened,
    the payout of a withdrawal omni holds, the clear of a paid one), and each at
    most once, so retrying a call is safe.


    ## Conventions


    - **Bodies** are JSON objects, at most 32 KiB (`/intents/solver`: 128 KiB).
    A body that is not a JSON object is a `422`, a larger one a `413`.

    - **Big integers.** Nonces and amounts are answered as decimal strings. In
    requests they may be decimal strings or JSON integers: integers above 2^53
    are read exactly (the bridge's nonces are about 1.8e21), but a decimal
    string is the safer choice for clients whose JSON encoder uses doubles.

    - **Nonces** are omni's: `unix seconds * 10^12 + n`.

    - **Encodings.** omni's token ids, receivers and the bridge signatures are
    base58; NEAR tx hashes are base58.

    - **Chain ids.** Chain ids are omni's (`v2_1.omni.hot.tg`), not always the
    chain's own: EVM chains use their EIP-155 id (Ethereum 1, Optimism 10, BNB
    56, Polygon 137, Monad 143, X Layer 196, Base 8453, Arbitrum 42161,
    Avalanche 43114, ...); the others have omni's numbers: Solana 1001, NEAR
    1010, Stellar 1100, TON 1117 (TON v1, 1111, is dead), Juno 4444118, Gonka
    4444119.

    - **Errors** are `{ "detail": "..." }` with an HTTP status (FastAPI's
    format, kept from HOR), the router's own `404`, `405` and `429` included.
    Clients should branch on the status and show or log the `detail`. A `5xx`
    (and a `502`/`503` in particular) is worth retrying with backoff; a `4xx`
    will answer the same until something changes on chain.

    - **CORS.** Any origin; the request's `Origin` is echoed with
    `access-control-allow-credentials: true`, and preflights allow `GET, POST,
    OPTIONS` with any header.

    - **Times** in answers are milliseconds since the epoch unless named `*_s`
    (seconds).


    ## Rate limits


    Per client IP (an IPv6 client by its /64), over 60 seconds, counted per
    Cloudflare location:


    | Class | Limit | Routes |

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

    | `bridge` | 300 / 60 s | `/withdraw/sign`, `/deposit/sign`, `/clear/sign`,
    `/relay/*`, `/bridge/*` |

    | `solver` | 120 / 60 s | `/intents/solver` |


    `/v1/health`, `/v1/time` and `/openapi.json` are not limited. Over the limit
    the answer is `429` `{ "detail": "Too many requests" }` with `Retry-After:
    60`.


    ## Load protection


    The MPC nodes are a fixed quorum: every signature is a round on each of
    them. So on top of the per-IP limits, every call that reaches the nodes (the
    `Signatures` routes, and the relay's own signing) is admitted globally,
    whoever asks:


    - **Rate per kind of signing**, by default 300 a minute each for
    withdrawals, deposits and clears: over it, `429` with `Retry-After`.

    - **Signings at once**, 60 in all, each kind its own share: over it, `503`
    `MPC nodes are busy, try again shortly` with `Retry-After`. Also `503` with
    `Retry-After` when the nodes answer `429` or too few of them are up.

    - **One signing per message.** A signature is kept for a day and answered
    again (a retry, another client, the relay), and while it is being made a
    second request waits for it (or gets `503` `This signature is being made,
    try again shortly` after 45 s). A refusal of the bridge (`400`) is answered
    again for 5 seconds.

    - **Refusals before the nodes**: a deposit omni already credited (`400`
    `Deposit … is already credited`), a withdrawal no payout can land (`400`
    `Withdrawal … : it can only be refunded`: it pays the token contract itself,
    the zero address, or a Stellar nonce past its 60 days).


    Retry a `429` or `503` after its `Retry-After`.
servers:
  - url: https://mpc.hex-api.app
    description: Production
security: []
tags:
  - name: Relay
    description: >-
      The recommended integration: the service sends the bridge's transactions
      and pays for them. Deposits are credited to NEAR Intents; withdrawals are
      paid out on their chain and cleared on omni.
  - name: Signatures
    description: >-
      The bridge's MPC signatures, for callers that submit the transactions
      themselves (HOR-compatible: same bodies, answers and errors). Each
      signature needs omni's word, and a deposit or clear also its AuthCall on
      chain, so a caller cannot forge or redirect one.
  - name: Registry
    description: >-
      The bridge registry: what users do on the bridge, as clients report it and
      as the relay sees it on chain. A post only records a claim: nothing is
      signed or sent for it, and what the relay reads on chain overrides it.
      Lookups answer 503 while the registry's database is not configured.
  - name: Monitor
    description: Health of every bridge HEX moves funds through, over 24 hours.
  - name: Intents
    description: >-
      NEAR Intents solver relay passthrough, used by HEX/HOT kit to publish
      signed intents.
  - name: Service
    description: Health, time and this document.
paths:
  /bridge/deposits:
    post:
      tags:
        - Registry
      summary: Record a deposit a user just sent
      description: >-
        Records a deposit by its source tx, with the account it is for (whose
        receivers are registered with it). The tx is read on its chain first:
        `422` when it made no bridge deposit or reverted, when the deposit's
        receiver is not the account's NEAR Intents receiver, or when the chain
        is one this service cannot read (Solana, TRON). A deposit read on chain
        is kept with its fields (`nonce`, `token`, `amount`, `receiver`) and the
        account its receiver is; a tx the chain does not show yet is kept as a
        claim and checked again later (dropped if it never shows). The row is
        unique on `(chain_id, tx)`. Nothing is credited: call `POST
        /relay/deposit` for that.
      operationId: registerDeposit
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RegisterDepositRequest'
            examples:
              stellar:
                summary: A Stellar deposit
                value:
                  chain_id: 1100
                  tx: >-
                    3b1f6c0e9d2a47c58e6f1a2b3c4d5e6f708192a3b4c5d6e7f8091a2b3c4d5e6f
                  intent_account: alice.near
      responses:
        '200':
          description: 'The row, or `recorded: false` without the database.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RegisterDepositAnswer'
              examples:
                recorded:
                  summary: Recorded
                  value:
                    recorded: true
                    deposit_hash: 6QPkTPp7EKZytMtEuvRmqGBBMMuwf4rrX4JjAoiuCYnT
                    deposit:
                      id: 812
                      chain_id: 1100
                      tx_hash: >-
                        3b1f6c0e9d2a47c58e6f1a2b3c4d5e6f708192a3b4c5d6e7f8091a2b3c4d5e6f
                      intent_account: alice.near
                      nonce: null
                      token: null
                      amount: null
                      receiver: null
                      near_tx: null
                      status: registered
                      attempts: 0
                      last_error: null
                      created_at: 1792944180000
                      updated_at: 1792944180000
                notRecorded:
                  summary: No database
                  value:
                    recorded: false
                    deposit_hash: 6QPkTPp7EKZytMtEuvRmqGBBMMuwf4rrX4JjAoiuCYnT
        '413':
          $ref: '#/components/responses/PayloadTooLarge'
        '422':
          description: A malformed field.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              examples:
                chain:
                  value:
                    detail: chain_id must be a chain id
                tx:
                  value:
                    detail: tx must be a tx hash
                account:
                  value:
                    detail: >-
                      intent_account must be a NEAR account, an EVM address or a
                      base58 key
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '500':
          $ref: '#/components/responses/InternalError'
components:
  schemas:
    RegisterDepositRequest:
      type: object
      required:
        - chain_id
        - tx
        - intent_account
      properties:
        chain_id:
          $ref: '#/components/schemas/ChainId'
        tx:
          type: string
          description: >-
            The source tx: 32-byte hex (lowercased; `0x` kept), or a
            base58/base64 hash (16–128 characters), kept as given.
          examples:
            - 3b1f6c0e9d2a47c58e6f1a2b3c4d5e6f708192a3b4c5d6e7f8091a2b3c4d5e6f
        intent_account:
          $ref: '#/components/schemas/IntentAccount'
    RegisterDepositAnswer:
      type: object
      required:
        - recorded
        - deposit_hash
      properties:
        recorded:
          type: boolean
          description: False without the database.
        deposit_hash:
          $ref: '#/components/schemas/Base58'
          description: The account's deposit receiver.
        deposit:
          $ref: '#/components/schemas/DepositRow'
    Error:
      type: object
      description: 'Every error: FastAPI''s `{ detail }` with the HTTP status.'
      required:
        - detail
      properties:
        detail:
          type: string
          description: What went wrong, readable.
      examples:
        - detail: Nonce was not used on target chain
    ChainId:
      type: integer
      minimum: 1
      description: >-
        Chain ids are omni's (`v2_1.omni.hot.tg`), not always the chain's own:
        EVM chains use their EIP-155 id (Ethereum 1, Optimism 10, BNB 56,
        Polygon 137, Monad 143, X Layer 196, Base 8453, Arbitrum 42161,
        Avalanche 43114, ...); the others have omni's numbers: Solana 1001, NEAR
        1010, Stellar 1100, TON 1117 (TON v1, 1111, is dead), Juno 4444118,
        Gonka 4444119.
      examples:
        - 1100
        - 1117
        - 137
        - 4444119
    IntentAccount:
      type: string
      description: >-
        A NEAR Intents account: a NEAR account (`alice.near`, a 64-hex implicit
        account), an EVM address, or a base58 32-byte key (a Solana address,
        taken as its hex implicit account).
      examples:
        - alice.near
        - '0xe4df1d74122c2a7b14481cbdde704fbd0a4f11a2'
    Base58:
      type: string
      pattern: ^[1-9A-HJ-NP-Za-km-z]+$
      description: Base58 (Bitcoin alphabet).
    DepositRow:
      type: object
      description: >-
        A deposit in the registry. What the client posted is a claim; the relay
        fills the rest from the chain.
      required:
        - id
        - chain_id
        - tx_hash
        - intent_account
        - nonce
        - token
        - amount
        - receiver
        - near_tx
        - status
        - attempts
        - last_error
        - created_at
        - updated_at
      properties:
        id:
          type: integer
        chain_id:
          $ref: '#/components/schemas/ChainId'
        tx_hash:
          type:
            - string
            - 'null'
          description: >-
            The source tx; null for a deposit the relay credited from its fields
            alone.
        intent_account:
          type:
            - string
            - 'null'
        nonce:
          type:
            - string
            - 'null'
          description: Decimal; known once the relay read the deposit.
        token:
          type:
            - string
            - 'null'
          description: omni's token id, base58.
        amount:
          type:
            - string
            - 'null'
          description: Decimal, in the token's smallest unit.
        receiver:
          type:
            - string
            - 'null'
          description: The deposit's receiver, base58.
        near_tx:
          type:
            - string
            - 'null'
          description: The relay's `mt_deposit_call` tx.
        status:
          type: string
          enum:
            - registered
            - credited
            - failed
        attempts:
          type: integer
          description: Failed relay attempts.
        last_error:
          type:
            - string
            - 'null'
        created_at:
          type: integer
          description: ms.
        updated_at:
          type: integer
          description: ms.
  responses:
    PayloadTooLarge:
      description: 'The body exceeds 32 KiB (`/intents/solver`: 128 KiB).'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          examples:
            tooLarge:
              value:
                detail: Body exceeds 32768 bytes
    TooManyRequests:
      description: >-
        Over the route's per-IP rate limit (60 s), or, on a route that signs,
        over the MPC nodes' signing rate (see Load protection). Wait
        `Retry-After` seconds.
      headers:
        Retry-After:
          $ref: '#/components/headers/RetryAfter'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          examples:
            limited:
              value:
                detail: Too many requests
            signing:
              value:
                detail: Too many bridge_deposit signings, try again in 1 s
    InternalError:
      description: An unexpected error. Its message is not exposed.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          examples:
            internal:
              value:
                detail: Internal Server Error
  headers:
    RetryAfter:
      description: Seconds to wait.
      schema:
        type: integer
      example: 60

````

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