openapi: 3.0.0
paths:
  /accounts:
    get:
      description: Returns every merchant account.
      operationId: listMerchantAccounts
      parameters: []
      responses:
        '200':
          description: ''
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TenantAccountListResponseDto'
        '400':
          description: Request validation failed (e.g. missing or malformed body / query).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
        '401':
          description: >-
            Missing or invalid `x-tenant-api-key` header. Code:
            `exceptions.auth.invalidApiKey`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
        '403':
          description: >-
            Request origin IP is not on the tenant API allowlist. Code:
            `exceptions.auth.ipNotAllowed`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
        '429':
          description: >-
            Rate limit exceeded for this endpoint. Retry after the window
            resets. Code: `exceptions.rateLimit.exceeded`. The
            `extension.msBeforeNext` field tells you how long to wait.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
        '500':
          description: >-
            Unexpected server error. Safe to retry idempotent operations after a
            backoff.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
      security:
        - TENANT_API_KEY: []
      summary: List merchant accounts
      tags:
        - Accounts
    post:
      description: 'Creates a new merchant account (display `name` in the JSON body). '
      operationId: createMerchantAccount
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateTenantAccountDto'
      responses:
        '201':
          description: Merchant account created.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TenantAccountResponseDto'
        '400':
          description: Validation error or max accounts per merchant reached.
        '401':
          description: >-
            Missing or invalid `x-tenant-api-key` header. Code:
            `exceptions.auth.invalidApiKey`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
        '403':
          description: >-
            Request origin IP is not on the tenant API allowlist. Code:
            `exceptions.auth.ipNotAllowed`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
        '429':
          description: >-
            Rate limit exceeded for this endpoint. Retry after the window
            resets. Code: `exceptions.rateLimit.exceeded`. The
            `extension.msBeforeNext` field tells you how long to wait.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
        '500':
          description: >-
            Unexpected server error. Safe to retry idempotent operations after a
            backoff.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
      security:
        - TENANT_API_KEY: []
      summary: Create a merchant account
      tags:
        - Accounts
  /currencies:
    get:
      description: >-
        Returns every crypto currency the platform supports together with their
        network, decimal places, deposit / withdrawal minimums, and the
        **effective** tenant-wide deposit commission. Optionally filterable by
        `network`.
      operationId: listCurrencies
      parameters:
        - name: network
          required: false
          in: query
          description: >-
            Optional filter: only return currencies on this network (e.g. `Tron`
            to fetch only TRC-20 assets).
          schema:
            type: string
            enum:
              - Tron
              - Solana
              - Ethereum
              - BNB
              - BTC
      responses:
        '200':
          description: ''
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantCurrencyListResponseDto'
        '400':
          description: Invalid `network` filter value.
        '401':
          description: >-
            Missing or invalid `x-tenant-api-key` header. Code:
            `exceptions.auth.invalidApiKey`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
        '403':
          description: >-
            Request origin IP is not on the tenant API allowlist. Code:
            `exceptions.auth.ipNotAllowed`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
        '429':
          description: >-
            Rate limit exceeded for this endpoint. Retry after the window
            resets. Code: `exceptions.rateLimit.exceeded`. The
            `extension.msBeforeNext` field tells you how long to wait.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
        '500':
          description: >-
            Unexpected server error. Safe to retry idempotent operations after a
            backoff.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
      security:
        - TENANT_API_KEY: []
      summary: List supported crypto currencies
      tags:
        - Currencies
  /currencies/fiat:
    get:
      description: >-
        Returns every fiat currency that can be used as `fiatCurrencyCode` on
        `POST /invoice`. Includes per-currency `minInvoiceAmount` so callers can
        validate their amounts client-side.
      operationId: listFiatCurrencies
      parameters: []
      responses:
        '200':
          description: ''
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantFiatCurrencyListResponseDto'
        '400':
          description: Request validation failed (e.g. missing or malformed body / query).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
        '401':
          description: >-
            Missing or invalid `x-tenant-api-key` header. Code:
            `exceptions.auth.invalidApiKey`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
        '403':
          description: >-
            Request origin IP is not on the tenant API allowlist. Code:
            `exceptions.auth.ipNotAllowed`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
        '429':
          description: >-
            Rate limit exceeded for this endpoint. Retry after the window
            resets. Code: `exceptions.rateLimit.exceeded`. The
            `extension.msBeforeNext` field tells you how long to wait.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
        '500':
          description: >-
            Unexpected server error. Safe to retry idempotent operations after a
            backoff.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
      security:
        - TENANT_API_KEY: []
      summary: List supported fiat (settlement) currencies
      tags:
        - Currencies
  /withdrawal/quote:
    post:
      description: >-
        Estimates the on-chain fee for the supplied withdrawal and returns a
        short-lived `quoteId` plus a fee breakdown. The quote does not reserve
        any balance and expires in ~60s. Submit the `quoteId` to `POST
        /withdrawal/commit` to actually create the withdrawal.
      operationId: createWithdrawalQuote
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WithdrawalQuoteRequestDto'
      responses:
        '200':
          description: ''
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WithdrawalQuoteDataResponseDto'
        '400':
          description: >-
            Validation error, currency/address mismatch, or below-minimum
            amount.
        '401':
          description: >-
            Missing or invalid `x-tenant-api-key` header. Code:
            `exceptions.auth.invalidApiKey`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
        '403':
          description: >-
            Request origin IP is not on the tenant API allowlist. Code:
            `exceptions.auth.ipNotAllowed`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
        '429':
          description: >-
            Rate limit exceeded for this endpoint. Retry after the window
            resets. Code: `exceptions.rateLimit.exceeded`. The
            `extension.msBeforeNext` field tells you how long to wait.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
        '500':
          description: >-
            Unexpected server error. Safe to retry idempotent operations after a
            backoff.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
      security:
        - TENANT_API_KEY: []
      summary: Quote a withdrawal
      tags:
        - Withdrawals
  /withdrawal/commit:
    post:
      description: >-
        Commits a previously-obtained `quoteId` and creates the withdrawal. The
        deduction currency, total deduction, and FX uplift were locked onto the
        quote at quote time; commit just locks that single balance, re-checks it
        still covers the locked total, and deducts inside a serializable
        transaction. If the locked balance has dropped below the locked total,
        commit returns `withdrawal.insufficientBalance` and the merchant must
        re-quote - commit does not retry against any other currency, even when
        cross-currency is enabled on the account.
      operationId: commitWithdrawalQuote
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CommitWithdrawalRequestDto'
      responses:
        '201':
          description: ''
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WithdrawalDataResponseDto'
        '400':
          description: >-
            Validation error, expired/already-committed quote, the locked
            balance no longer covers the quote, or duplicate `orderId`.
        '401':
          description: >-
            Missing or invalid `x-tenant-api-key` header. Code:
            `exceptions.auth.invalidApiKey`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
        '403':
          description: >-
            Request origin IP is not on the tenant API allowlist. Code:
            `exceptions.auth.ipNotAllowed`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
        '429':
          description: >-
            Rate limit exceeded for this endpoint. Retry after the window
            resets. Code: `exceptions.rateLimit.exceeded`. The
            `extension.msBeforeNext` field tells you how long to wait.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
        '500':
          description: >-
            Unexpected server error. Safe to retry idempotent operations after a
            backoff.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
      security:
        - TENANT_API_KEY: []
      summary: Commit a withdrawal quote
      tags:
        - Withdrawals
  /withdrawal/list:
    get:
      description: >-
        Returns withdrawals for the `accountId` query parameter (must belong to
        your tenant), most recent first. Paginated.
      operationId: listWithdrawals
      parameters:
        - name: page
          required: false
          in: query
          description: 1-indexed page number.
          schema:
            minimum: 1
            default: 1
            type: number
        - name: limit
          required: false
          in: query
          description: Items per page. Capped at 100.
          schema:
            minimum: 1
            maximum: 100
            default: 20
            type: number
        - name: accountId
          required: true
          in: query
          description: >-
            Tenant account whose withdrawals to list. The merchant API key
            authenticates your tenant. Only this field selects the account for
            this request.
          schema:
            format: uuid
            type: string
        - name: status
          required: false
          in: query
          description: Filter by withdrawal status.
          schema:
            type: string
            enum:
              - created
              - processing
              - completed
              - failed
              - cancelled
      responses:
        '200':
          description: ''
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WithdrawalListResponseDto'
        '400':
          description: Request validation failed (e.g. missing or malformed body / query).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
        '401':
          description: >-
            Missing or invalid `x-tenant-api-key` header. Code:
            `exceptions.auth.invalidApiKey`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
        '403':
          description: >-
            Request origin IP is not on the tenant API allowlist. Code:
            `exceptions.auth.ipNotAllowed`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
        '429':
          description: >-
            Rate limit exceeded for this endpoint. Retry after the window
            resets. Code: `exceptions.rateLimit.exceeded`. The
            `extension.msBeforeNext` field tells you how long to wait.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
        '500':
          description: >-
            Unexpected server error. Safe to retry idempotent operations after a
            backoff.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
      security:
        - TENANT_API_KEY: []
      summary: List withdrawals
      tags:
        - Withdrawals
  /withdrawal:
    get:
      description: >-
        Retrieves a single withdrawal by its `id` (UUID) or the merchant
        `orderId`. Requires `accountId`. At least one of the two query
        parameters must be supplied; if both are present, `id` takes precedence.
      operationId: getWithdrawal
      parameters:
        - name: accountId
          required: true
          in: query
          description: >-
            Tenant account that owns the withdrawal. The merchant API key
            authenticates your tenant. Only this field selects the account for
            this request.
          schema:
            format: uuid
            type: string
        - name: id
          required: false
          in: query
          description: >-
            Withdrawal ID (UUID) returned from `POST /withdrawal`. Mutually
            optional with `orderId`.
          schema:
            format: uuid
            type: string
        - name: orderId
          required: false
          in: query
          description: >-
            Merchant `orderId` supplied when the withdrawal was created.
            Mutually optional with `id`.
          schema:
            type: string
      responses:
        '200':
          description: ''
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WithdrawalDataResponseDto'
        '400':
          description: >-
            Neither `id` nor `orderId` was supplied, or a supplied value failed
            validation.
        '401':
          description: >-
            Missing or invalid `x-tenant-api-key` header. Code:
            `exceptions.auth.invalidApiKey`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
        '403':
          description: >-
            Request origin IP is not on the tenant API allowlist. Code:
            `exceptions.auth.ipNotAllowed`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
        '404':
          description: Withdrawal not found.
        '429':
          description: >-
            Rate limit exceeded for this endpoint. Retry after the window
            resets. Code: `exceptions.rateLimit.exceeded`. The
            `extension.msBeforeNext` field tells you how long to wait.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
        '500':
          description: >-
            Unexpected server error. Safe to retry idempotent operations after a
            backoff.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
      security:
        - TENANT_API_KEY: []
      summary: Retrieve a withdrawal
      tags:
        - Withdrawals
  /webhooks/invoice.statusChanged:
    post:
      description: >-
        Reference schema for outbound webhooks Cryptonly POSTs to your
        configured HTTPS `webhookUrl`. Each delivery includes an
        `x-webhook-signature` header (HMAC-SHA256 over the raw JSON body). This
        route exists for Swagger documentation only; implement verification and
        handling on your own server.
      operationId: webhookReferenceInvoiceStatusChanged
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/InvoiceStatusChangedWebhookBodyDto'
            examples:
              default:
                summary: Sample invoice.statusChanged payload
                value:
                  event: invoice.statusChanged
                  data:
                    id: 6339238d-66c3-4b8f-b7b3-493c654a6cad
                    accountId: bc6302f0-59e0-4c41-9914-611e23f6a164
                    orderId: order_webhook_reference_001
                    amount: 49.99
                    fiatCurrencyCode: USD
                    items: []
                    status: paid
                    cryptoCurrencyCode: USDT_TRC20
                    cryptoAmountExpected: 50
                    cryptoAmountReceived: 50
                    settlement:
                      amountPaid: 50
                      amountPaidUsd: 50
                      commissionAmount: 0.5
                      commissionAmountUsd: 0.5
                      networkFeeAmount: 1
                      networkFeeAmountUsd: 0.1
                      networkFeeCurrencyCode: TRX
                      netAmount: 49.5
                      netAmountUsd: 49.5
                      completedAt: '2026-07-31T05:39:42.670Z'
                    description: Webhook reference example
                    expiresAt: '2026-07-31T05:39:42.669Z'
                    createdAt: '2026-07-31T05:39:42.669Z'
                    source: api
                    paymentPageUrl: https://payment.cryptonly.com/invoice/test-webhook-token
                    paidAt: '2026-07-31T05:39:42.670Z'
                  timestamp: '2026-01-01T12:00:00.000Z'
      responses:
        '200':
          description: Reference endpoint acknowledged.
        '400':
          description: Request validation failed (e.g. missing or malformed body / query).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
        '401':
          description: >-
            Missing or invalid `x-tenant-api-key` header. Code:
            `exceptions.auth.invalidApiKey`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
        '403':
          description: >-
            Request origin IP is not on the tenant API allowlist. Code:
            `exceptions.auth.ipNotAllowed`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
        '429':
          description: >-
            Rate limit exceeded for this endpoint. Retry after the window
            resets. Code: `exceptions.rateLimit.exceeded`. The
            `extension.msBeforeNext` field tells you how long to wait.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
        '500':
          description: >-
            Unexpected server error. Safe to retry idempotent operations after a
            backoff.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
      security:
        - TENANT_API_KEY: []
      summary: 'Webhook reference: invoice.statusChanged'
      tags:
        - Webhooks
  /webhooks/deposit.statusChanged:
    post:
      description: >-
        Reference schema for outbound webhooks Cryptonly POSTs to your
        configured HTTPS `webhookUrl`. Each delivery includes an
        `x-webhook-signature` header (HMAC-SHA256 over the raw JSON body). This
        route exists for Swagger documentation only; implement verification and
        handling on your own server.
      operationId: webhookReferenceDepositStatusChanged
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/DepositStatusChangedWebhookBodyDto'
            examples:
              default:
                summary: Sample deposit.statusChanged payload
                value:
                  event: deposit.statusChanged
                  data:
                    id: 4c6b570a-1fe6-46f9-a46f-c50e560c3eb1
                    accountId: 71d87715-a54b-4aef-a032-d5a05b7511cc
                    orderId: order_webhook_reference_001
                    status: completed
                    cryptoCurrencyCode: USDT_TRC20
                    address: TJn22ewJPN89yNtrnBkagsunbrLnPyQCgs
                    expiresAt: '2026-07-31T05:39:42.670Z'
                    createdAt: '2026-07-31T05:39:42.670Z'
                    updatedAt: '2026-07-31T05:39:42.670Z'
                    previousStatus: processing
                    depositTransactionHash: >-
                      0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
                    actuallyReceivedAmount: 50
                    actuallyReceivedAmountUsd: 50
                  timestamp: '2026-01-01T12:00:00.000Z'
      responses:
        '200':
          description: Reference endpoint acknowledged.
        '400':
          description: Request validation failed (e.g. missing or malformed body / query).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
        '401':
          description: >-
            Missing or invalid `x-tenant-api-key` header. Code:
            `exceptions.auth.invalidApiKey`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
        '403':
          description: >-
            Request origin IP is not on the tenant API allowlist. Code:
            `exceptions.auth.ipNotAllowed`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
        '429':
          description: >-
            Rate limit exceeded for this endpoint. Retry after the window
            resets. Code: `exceptions.rateLimit.exceeded`. The
            `extension.msBeforeNext` field tells you how long to wait.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
        '500':
          description: >-
            Unexpected server error. Safe to retry idempotent operations after a
            backoff.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
      security:
        - TENANT_API_KEY: []
      summary: 'Webhook reference: deposit.statusChanged'
      tags:
        - Webhooks
  /webhooks/withdrawal.statusChanged:
    post:
      description: >-
        Reference schema for outbound webhooks Cryptonly POSTs to your
        configured HTTPS `webhookUrl`. Each delivery includes an
        `x-webhook-signature` header (HMAC-SHA256 over the raw JSON body). This
        route exists for Swagger documentation only; implement verification and
        handling on your own server.
      operationId: webhookReferenceWithdrawalStatusChanged
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WithdrawalStatusChangedWebhookBodyDto'
            examples:
              default:
                summary: Sample withdrawal.statusChanged payload
                value:
                  event: withdrawal.statusChanged
                  data:
                    id: b3d9d91b-3efd-4c63-9779-115febdb387c
                    orderId: order_webhook_reference_001
                    accountId: 2d5c53d1-8f82-4697-adde-808c9b2d078d
                    cryptoCurrencyCode: ETH
                    address: '0x1111111111111111111111111111111111111111'
                    amount: 100
                    transactionHash: >-
                      0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
                    status: completed
                    previousStatus: processing
                    convertId: null
                    feeAmount: 1
                    feeAmountUsd: 1
                    amountUsd: 100
                    debitedAmount: 101
                    createdAt: '2026-07-31T05:39:42.670Z'
                    updatedAt: '2026-07-31T05:39:42.670Z'
                    quoteId: 0f8bcae0-2a97-4f83-af61-0f8a2f932845
                    transferId: 1448d2d5-3252-45d4-9aa7-be7b19a7e9e6
                    source: api
                  timestamp: '2026-01-01T12:00:00.000Z'
      responses:
        '200':
          description: Reference endpoint acknowledged.
        '400':
          description: Request validation failed (e.g. missing or malformed body / query).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
        '401':
          description: >-
            Missing or invalid `x-tenant-api-key` header. Code:
            `exceptions.auth.invalidApiKey`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
        '403':
          description: >-
            Request origin IP is not on the tenant API allowlist. Code:
            `exceptions.auth.ipNotAllowed`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
        '429':
          description: >-
            Rate limit exceeded for this endpoint. Retry after the window
            resets. Code: `exceptions.rateLimit.exceeded`. The
            `extension.msBeforeNext` field tells you how long to wait.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
        '500':
          description: >-
            Unexpected server error. Safe to retry idempotent operations after a
            backoff.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
      security:
        - TENANT_API_KEY: []
      summary: 'Webhook reference: withdrawal.statusChanged'
      tags:
        - Webhooks
  /deposit:
    post:
      description: >-
        Returns a pool address and QR code for a flexible crypto top-up.
        Requires `accountId`, `cryptoCurrencyCode`, and merchant `orderId`.
      operationId: createDeposit
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateDepositApiKeyRequestDto'
      responses:
        '201':
          description: ''
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DepositCreatedResponseDto'
        '400':
          description: Request validation failed (e.g. missing or malformed body / query).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
        '401':
          description: >-
            Missing or invalid `x-tenant-api-key` header. Code:
            `exceptions.auth.invalidApiKey`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
        '403':
          description: >-
            Request origin IP is not on the tenant API allowlist. Code:
            `exceptions.auth.ipNotAllowed`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
        '409':
          description: >-
            A deposit with the same `orderId` already exists in a terminal
            state.
        '429':
          description: >-
            Rate limit exceeded for this endpoint. Retry after the window
            resets. Code: `exceptions.rateLimit.exceeded`. The
            `extension.msBeforeNext` field tells you how long to wait.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
        '500':
          description: >-
            Unexpected server error. Safe to retry idempotent operations after a
            backoff.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
      security:
        - TENANT_API_KEY: []
      summary: Create a crypto top-up deposit
      tags:
        - Deposits
    get:
      operationId: getDeposit
      parameters:
        - name: accountId
          required: true
          in: query
          schema:
            format: uuid
            type: string
        - name: id
          required: false
          in: query
          schema:
            format: uuid
            type: string
        - name: orderId
          required: false
          in: query
          schema:
            type: string
      responses:
        '200':
          description: ''
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TenantApiKeyDepositDataResponseDto'
        '400':
          description: Request validation failed (e.g. missing or malformed body / query).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
        '401':
          description: >-
            Missing or invalid `x-tenant-api-key` header. Code:
            `exceptions.auth.invalidApiKey`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
        '403':
          description: >-
            Request origin IP is not on the tenant API allowlist. Code:
            `exceptions.auth.ipNotAllowed`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
        '404':
          description: Deposit not found.
        '429':
          description: >-
            Rate limit exceeded for this endpoint. Retry after the window
            resets. Code: `exceptions.rateLimit.exceeded`. The
            `extension.msBeforeNext` field tells you how long to wait.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
        '500':
          description: >-
            Unexpected server error. Safe to retry idempotent operations after a
            backoff.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
      security:
        - TENANT_API_KEY: []
      summary: Retrieve a deposit
      tags:
        - Deposits
  /deposit/list:
    get:
      operationId: listDeposits
      parameters:
        - name: page
          required: false
          in: query
          description: 1-indexed page number.
          schema:
            minimum: 1
            default: 1
            type: number
        - name: limit
          required: false
          in: query
          description: Items per page. Capped at 100.
          schema:
            minimum: 1
            maximum: 100
            default: 20
            type: number
        - name: accountId
          required: true
          in: query
          schema:
            format: uuid
            type: string
        - name: status
          required: false
          in: query
          schema:
            type: string
            enum:
              - created
              - processing
              - completed
              - suspended
              - failed
              - expired
              - cancelled
      responses:
        '200':
          description: ''
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DepositListResponseDto'
        '400':
          description: Request validation failed (e.g. missing or malformed body / query).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
        '401':
          description: >-
            Missing or invalid `x-tenant-api-key` header. Code:
            `exceptions.auth.invalidApiKey`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
        '403':
          description: >-
            Request origin IP is not on the tenant API allowlist. Code:
            `exceptions.auth.ipNotAllowed`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
        '429':
          description: >-
            Rate limit exceeded for this endpoint. Retry after the window
            resets. Code: `exceptions.rateLimit.exceeded`. The
            `extension.msBeforeNext` field tells you how long to wait.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
        '500':
          description: >-
            Unexpected server error. Safe to retry idempotent operations after a
            backoff.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
      security:
        - TENANT_API_KEY: []
      summary: List merchant top-up deposits
      tags:
        - Deposits
  /address-provision:
    post:
      description: >-
        Returns a provision id, address, and QR. Address validity defaults to 30
        minutes (optional expiresInMinutes: 15–90). Each inbound transfer at or
        above the minimum creates a separate deposit record.
      operationId: createAddressProvision
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateAddressProvisionApiKeyRequestDto'
      responses:
        '201':
          description: ''
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AddressProvisionCreatedResponseDto'
        '400':
          description: Request validation failed (e.g. missing or malformed body / query).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
        '401':
          description: >-
            Missing or invalid `x-tenant-api-key` header. Code:
            `exceptions.auth.invalidApiKey`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
        '403':
          description: >-
            Request origin IP is not on the tenant API allowlist. Code:
            `exceptions.auth.ipNotAllowed`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
        '429':
          description: >-
            Rate limit exceeded for this endpoint. Retry after the window
            resets. Code: `exceptions.rateLimit.exceeded`. The
            `extension.msBeforeNext` field tells you how long to wait.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
        '500':
          description: >-
            Unexpected server error. Safe to retry idempotent operations after a
            backoff.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
      security:
        - TENANT_API_KEY: []
      summary: Reserve a pool address for repeated top-ups
      tags:
        - Address provision
    get:
      operationId: getAddressProvision
      parameters:
        - name: accountId
          required: true
          in: query
          schema:
            format: uuid
            type: string
        - name: id
          required: true
          in: query
          description: Address provision id.
          schema:
            format: uuid
            type: string
      responses:
        '200':
          description: ''
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AddressProvisionGetResponseDto'
        '400':
          description: Request validation failed (e.g. missing or malformed body / query).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
        '401':
          description: >-
            Missing or invalid `x-tenant-api-key` header. Code:
            `exceptions.auth.invalidApiKey`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
        '403':
          description: >-
            Request origin IP is not on the tenant API allowlist. Code:
            `exceptions.auth.ipNotAllowed`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
        '404':
          description: ''
        '429':
          description: >-
            Rate limit exceeded for this endpoint. Retry after the window
            resets. Code: `exceptions.rateLimit.exceeded`. The
            `extension.msBeforeNext` field tells you how long to wait.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
        '500':
          description: >-
            Unexpected server error. Safe to retry idempotent operations after a
            backoff.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
      security:
        - TENANT_API_KEY: []
      summary: Get an address provision
      tags:
        - Address provision
  /invoice:
    post:
      description: >-
        Creates a new invoice for the `accountId` in the body (must belong to
        your tenant). The response includes a hosted payment page URL your
        customer can use to complete payment in crypto.
      operationId: createInvoice
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateInvoiceApiKeyRequestDto'
      responses:
        '201':
          description: Invoice created.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/InvoiceCreatedResponseDto'
        '400':
          description: >-
            Validation error, missing fiat currency, amount below the configured
            minimum, or the referenced `customerId` is blocked
            (`exceptions.invoice.customerBlocked`).
        '401':
          description: >-
            Missing or invalid `x-tenant-api-key` header. Code:
            `exceptions.auth.invalidApiKey`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
        '403':
          description: >-
            Request origin IP is not on the tenant API allowlist. Code:
            `exceptions.auth.ipNotAllowed`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
        '409':
          description: An invoice with the supplied `orderId` already exists.
        '429':
          description: >-
            Rate limit exceeded for this endpoint. Retry after the window
            resets. Code: `exceptions.rateLimit.exceeded`. The
            `extension.msBeforeNext` field tells you how long to wait.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
        '500':
          description: >-
            Unexpected server error. Safe to retry idempotent operations after a
            backoff.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
      security:
        - TENANT_API_KEY: []
      summary: Create an invoice
      tags:
        - Invoices
    get:
      description: >-
        Retrieves a single invoice by its `id` (UUID) or the merchant `orderId`.
        Requires `accountId`. At least one of `id` or `orderId` must be
        supplied; if both are present, `id` takes precedence. The response
        always includes `paymentPageUrl` for the hosted payment page.
      operationId: getInvoice
      parameters:
        - name: accountId
          required: true
          in: query
          description: >-
            Account that owns the invoice. The merchant API key authenticates
            your tenant. Only this field selects the account for this request.
          schema:
            format: uuid
            type: string
        - name: id
          required: false
          in: query
          description: >-
            Invoice ID (UUID) returned from `POST /invoice`. Mutually optional
            with `orderId`.
          schema:
            format: uuid
            type: string
        - name: orderId
          required: false
          in: query
          description: >-
            Merchant `orderId` supplied when the invoice was created. Mutually
            optional with `id`.
          schema:
            type: string
      responses:
        '200':
          description: ''
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TenantApiKeyInvoiceDataResponseDto'
        '400':
          description: >-
            Neither `id` nor `orderId` was supplied, or a supplied value failed
            validation.
        '401':
          description: >-
            Missing or invalid `x-tenant-api-key` header. Code:
            `exceptions.auth.invalidApiKey`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
        '403':
          description: >-
            Request origin IP is not on the tenant API allowlist. Code:
            `exceptions.auth.ipNotAllowed`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
        '404':
          description: Invoice not found.
        '429':
          description: >-
            Rate limit exceeded for this endpoint. Retry after the window
            resets. Code: `exceptions.rateLimit.exceeded`. The
            `extension.msBeforeNext` field tells you how long to wait.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
        '500':
          description: >-
            Unexpected server error. Safe to retry idempotent operations after a
            backoff.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
      security:
        - TENANT_API_KEY: []
      summary: Retrieve an invoice
      tags:
        - Invoices
  /invoice/list:
    get:
      description: >-
        Returns invoices for the `accountId` query parameter (must belong to
        your tenant), most recent first. Paginated. Each item includes
        `paymentPageUrl` for the hosted payment page.
      operationId: listInvoices
      parameters:
        - name: page
          required: false
          in: query
          description: 1-indexed page number.
          schema:
            minimum: 1
            default: 1
            type: number
        - name: limit
          required: false
          in: query
          description: Items per page. Capped at 100.
          schema:
            minimum: 1
            maximum: 100
            default: 20
            type: number
        - name: accountId
          required: true
          in: query
          description: >-
            Tenant account whose invoices to list. The merchant API key
            authenticates your tenant. Only this field selects the account for
            this request.
          schema:
            format: uuid
            type: string
        - name: status
          required: false
          in: query
          description: Filter by invoice status.
          schema:
            type: string
            enum:
              - created
              - processing
              - paid
              - partially_paid
              - overpaid
              - expired
              - cancelled
              - failed
              - suspended
      responses:
        '200':
          description: ''
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/InvoiceListResponseDto'
        '400':
          description: Request validation failed (e.g. missing or malformed body / query).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
        '401':
          description: >-
            Missing or invalid `x-tenant-api-key` header. Code:
            `exceptions.auth.invalidApiKey`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
        '403':
          description: >-
            Request origin IP is not on the tenant API allowlist. Code:
            `exceptions.auth.ipNotAllowed`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
        '429':
          description: >-
            Rate limit exceeded for this endpoint. Retry after the window
            resets. Code: `exceptions.rateLimit.exceeded`. The
            `extension.msBeforeNext` field tells you how long to wait.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
        '500':
          description: >-
            Unexpected server error. Safe to retry idempotent operations after a
            backoff.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
      security:
        - TENANT_API_KEY: []
      summary: List invoices
      tags:
        - Invoices
  /invoice/cancel:
    post:
      description: >-
        Cancels an invoice that has not been paid yet. Requires `accountId`
        (must belong to your tenant). The invoice is identified by either `id`
        or merchant `orderId` - at least one is required. Returns 400 if the
        invoice has already been settled or cancelled.
      operationId: cancelInvoice
      parameters:
        - name: accountId
          required: true
          in: query
          description: >-
            Account that owns the invoice. The merchant API key authenticates
            your tenant. Only this field selects the account for this request.
          schema:
            format: uuid
            type: string
        - name: id
          required: false
          in: query
          description: >-
            Invoice ID (UUID) returned from `POST /invoice`. Mutually optional
            with `orderId`.
          schema:
            format: uuid
            type: string
        - name: orderId
          required: false
          in: query
          description: >-
            Merchant `orderId` supplied when the invoice was created. Mutually
            optional with `id`.
          schema:
            type: string
      responses:
        '204':
          description: Invoice cancelled.
        '400':
          description: >-
            Invoice cannot be cancelled in its current status, or neither `id`
            nor `orderId` was supplied.
        '401':
          description: >-
            Missing or invalid `x-tenant-api-key` header. Code:
            `exceptions.auth.invalidApiKey`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
        '403':
          description: >-
            Request origin IP is not on the tenant API allowlist. Code:
            `exceptions.auth.ipNotAllowed`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
        '404':
          description: Invoice not found.
        '429':
          description: >-
            Rate limit exceeded for this endpoint. Retry after the window
            resets. Code: `exceptions.rateLimit.exceeded`. The
            `extension.msBeforeNext` field tells you how long to wait.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
        '500':
          description: >-
            Unexpected server error. Safe to retry idempotent operations after a
            backoff.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
      security:
        - TENANT_API_KEY: []
      summary: Cancel an invoice
      tags:
        - Invoices
  /zapier/subscribe:
    post:
      description: >-
        Registers a Zapier hook URL to receive Cryptonly webhook events. Used by
        the Cryptonly Zapier integration when a user enables a Zap.
      operationId: zapierSubscribe
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ZapierSubscribeRequestDto'
      responses:
        '201':
          description: ''
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ZapierSubscribeResponseDto'
        '400':
          description: Request validation failed (e.g. missing or malformed body / query).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
        '401':
          description: >-
            Missing or invalid `x-tenant-api-key` header. Code:
            `exceptions.auth.invalidApiKey`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
        '403':
          description: >-
            Request origin IP is not on the tenant API allowlist. Code:
            `exceptions.auth.ipNotAllowed`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
        '429':
          description: >-
            Rate limit exceeded for this endpoint. Retry after the window
            resets. Code: `exceptions.rateLimit.exceeded`. The
            `extension.msBeforeNext` field tells you how long to wait.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
        '500':
          description: >-
            Unexpected server error. Safe to retry idempotent operations after a
            backoff.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
      security:
        - TENANT_API_KEY: []
      summary: Subscribe a Zapier REST Hook target URL
      tags:
        - Zapier Integration
  /zapier/subscribe/{id}:
    delete:
      description: Removes a Zapier hook subscription when a user disables a Zap.
      operationId: zapierUnsubscribe
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        '204':
          description: ''
        '400':
          description: Request validation failed (e.g. missing or malformed body / query).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
        '401':
          description: >-
            Missing or invalid `x-tenant-api-key` header. Code:
            `exceptions.auth.invalidApiKey`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
        '403':
          description: >-
            Request origin IP is not on the tenant API allowlist. Code:
            `exceptions.auth.ipNotAllowed`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
        '404':
          description: Subscription not found
        '429':
          description: >-
            Rate limit exceeded for this endpoint. Retry after the window
            resets. Code: `exceptions.rateLimit.exceeded`. The
            `extension.msBeforeNext` field tells you how long to wait.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
        '500':
          description: >-
            Unexpected server error. Safe to retry idempotent operations after a
            backoff.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MerchantApiErrorResponseDto'
      security:
        - TENANT_API_KEY: []
      summary: Unsubscribe a Zapier REST Hook target URL
      tags:
        - Zapier Integration
info:
  title: Cryptonly Merchant API
  description: >-
    Server-to-server API authenticated with a tenant API key (sent via the
    `x-tenant-api-key` header). Keys identify your tenant only; each endpoint
    documents where to pass `accountId` (body or query) to select the tenant
    account the operation applies to.


    Errors are returned with a stable JSON envelope: `{ "code":
    "exceptions.<area>.<reason>", "message": "...", "extension": { ... } }`.
    Branch on `code` rather than parsing `message`.
  version: '1.0'
  contact: {}
tags: []
servers:
  - url: '["https://api-merchant.cryptonly.net"'
  - url: '"https://sandbox-api-merchant.cryptonly.net"]'
components:
  securitySchemes:
    TENANT_API_KEY:
      type: apiKey
      in: header
      name: x-tenant-api-key
      description: >-
        Secret key from the merchant dashboard. Authenticates your tenant.
        Endpoints still require an explicit `accountId` in the body or query
        where the route defines it.
  schemas:
    TenantAccountListResponseDto:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/TenantAccountDto'
      required:
        - data
    MerchantApiErrorResponseDto:
      type: object
      properties:
        code:
          type: string
          description: >-
            Stable machine-readable error code, namespaced under `exceptions.`.
            Always prefer branching on this value over `message`. See the
            per-route `description`s for the codes that route emits.
          example: exceptions.auth.invalidApiKey
        message:
          type: string
          description: >-
            Human-readable explanation. Subject to wording changes; for
            programmatic checks use `code` instead.
          example: Invalid or missing API key
        extension:
          type: object
          description: >-
            Optional structured payload accompanying the error. For
            `exceptions.rateLimit.exceeded` includes `msBeforeNext`; for
            validation errors includes the offending field info.
          additionalProperties: true
          nullable: true
      required:
        - code
        - message
    CreateTenantAccountDto:
      type: object
      properties:
        name:
          type: string
          description: Display name for the account
      required:
        - name
    TenantAccountResponseDto:
      type: object
      properties:
        data:
          $ref: '#/components/schemas/TenantAccountDto'
      required:
        - data
    MerchantCurrencyListResponseDto:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/MerchantCurrencyDto'
      required:
        - data
    MerchantFiatCurrencyListResponseDto:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/MerchantFiatCurrencyDto'
      required:
        - data
    WithdrawalQuoteRequestDto:
      type: object
      properties:
        accountId:
          type: string
          description: >-
            Account ID (must belong to your tenant). The merchant API key
            authenticates your tenant. Only this field selects the account for
            this request.
          format: uuid
        cryptoCurrencyCode:
          type: string
          description: Currency code.
          example: USDT_TRC20
          enum:
            - USDT_TRC20
            - USDT_ERC20
            - USDT_BEP20
            - USDC_ERC20
            - USDC_BEP20
            - ETH
            - TRX
            - BNB
            - BTC
        address:
          type: string
          description: Destination wallet address
        amount:
          type: number
          description: Withdrawal amount in `cryptoCurrencyCode`
          example: 100
        allowAutoConvert:
          type: boolean
          description: >-
            If true and the withdrawal-asset balance is short of amount +
            on-chain fee, the quote may add a `currency_conversion` to top up
            that balance ($0.5 USD flat commission in the source currency)
            before a normal same-currency withdrawal. Commit reuses the locked
            `currency_conversion` row.
          default: false
        orderId:
          type: string
          description: >-
            Merchant idempotency key, scoped to (tenant, account). Two quote
            requests sharing an `orderId` collapse to the same quote, and the
            pair `(orderId, account)` can ever back at most one committed
            withdrawal - re-quoting after commit fails with `409`.
      required:
        - accountId
        - cryptoCurrencyCode
        - address
        - amount
        - orderId
    WithdrawalQuoteDataResponseDto:
      type: object
      properties:
        data:
          $ref: '#/components/schemas/WithdrawalQuoteResponseDto'
      required:
        - data
    CommitWithdrawalRequestDto:
      type: object
      properties:
        quoteId:
          type: string
          description: Quote id from `POST /withdrawal/quote`.
          format: uuid
        customData:
          type: object
          description: Custom metadata
        webhookUrl:
          type: string
          description: >-
            HTTPS URL to receive webhook notifications. Must be a public,
            TLD-qualified HTTPS URL.
          example: https://merchant.example.com/webhooks/cryptonly/withdrawals
      required:
        - quoteId
    WithdrawalDataResponseDto:
      type: object
      properties:
        data:
          $ref: '#/components/schemas/WithdrawalDto'
      required:
        - data
    WithdrawalListResponseDto:
      type: object
      properties:
        total:
          type: number
          description: Total number of matching rows.
        page:
          type: number
          description: 1-indexed page number that was returned.
        limit:
          type: number
          description: Items per page that were returned.
        hasMore:
          type: boolean
          description: True if there is at least one more page after this one.
        data:
          type: array
          items:
            $ref: '#/components/schemas/WithdrawalDto'
      required:
        - total
        - page
        - limit
        - hasMore
        - data
    InvoiceStatusChangedWebhookBodyDto:
      type: object
      properties:
        event:
          type: string
          enum:
            - invoice.statusChanged
          example: invoice.statusChanged
        data:
          $ref: '#/components/schemas/InvoiceStatusChangedWebhookDataDto'
        timestamp:
          type: string
          description: ISO 8601 timestamp when Cryptonly signed and sent the webhook.
          example: '2026-01-01T12:00:00.000Z'
      required:
        - event
        - data
        - timestamp
    DepositStatusChangedWebhookBodyDto:
      type: object
      properties:
        event:
          type: string
          enum:
            - deposit.statusChanged
          example: deposit.statusChanged
        data:
          $ref: '#/components/schemas/DepositStatusChangedWebhookDataDto'
        timestamp:
          type: string
          description: ISO 8601 timestamp when Cryptonly signed and sent the webhook.
          example: '2026-01-01T12:00:00.000Z'
      required:
        - event
        - data
        - timestamp
    WithdrawalStatusChangedWebhookBodyDto:
      type: object
      properties:
        event:
          type: string
          enum:
            - withdrawal.statusChanged
          example: withdrawal.statusChanged
        data:
          $ref: '#/components/schemas/WithdrawalStatusChangedWebhookDataDto'
        timestamp:
          type: string
          description: ISO 8601 timestamp when Cryptonly signed and sent the webhook.
          example: '2026-01-01T12:00:00.000Z'
      required:
        - event
        - data
        - timestamp
    CreateDepositApiKeyRequestDto:
      type: object
      properties:
        accountId:
          type: string
          format: uuid
        cryptoCurrencyCode:
          type: string
          description: Crypto currency code.
          example: USDT_TRC20
          enum:
            - USDT_TRC20
            - USDT_ERC20
            - USDT_BEP20
            - USDC_ERC20
            - USDC_BEP20
            - ETH
            - TRX
            - BNB
            - BTC
        orderId:
          type: string
          description: Merchant idempotency key (unique per account).
        customerId:
          type: string
          description: Optional merchant customer reference.
        webhookUrl:
          type: string
          description: >-
            HTTPS webhook for deposit status events. Overrides tenant default
            deposit webhook.
          example: https://merchant.example.com/webhooks/cryptonly/deposits
      required:
        - accountId
        - cryptoCurrencyCode
        - orderId
    DepositCreatedResponseDto:
      type: object
      properties:
        data:
          $ref: '#/components/schemas/DepositCreateDataDto'
      required:
        - data
    TenantApiKeyDepositDataResponseDto:
      type: object
      properties:
        data:
          $ref: '#/components/schemas/TenantApiKeyDepositResponseDto'
      required:
        - data
    DepositListResponseDto:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/TenantApiKeyDepositResponseDto'
        total:
          type: number
        page:
          type: number
        limit:
          type: number
        hasMore:
          type: boolean
          description: True if there is at least one more page after this one.
      required:
        - data
        - total
        - page
        - limit
        - hasMore
    CreateAddressProvisionApiKeyRequestDto:
      type: object
      properties:
        accountId:
          type: string
          format: uuid
        cryptoCurrencyCode:
          type: string
          description: Crypto currency code.
          example: USDT_TRC20
          enum:
            - USDT_TRC20
            - USDT_ERC20
            - USDT_BEP20
            - USDC_ERC20
            - USDC_BEP20
            - ETH
            - TRX
            - BNB
            - BTC
        customerId:
          type: string
          description: >-
            Your customer identifier. An active provision for the same customer
            + currency is returned instead of creating a duplicate.
        expiresInMinutes:
          type: number
          description: >-
            How long the deposit address stays valid, in minutes. Defaults to
            30.
          minimum: 15
          maximum: 90
          default: 30
        webhookUrl:
          type: string
          description: >-
            HTTPS webhook for each payment deposit under this provision.
            Overrides tenant default deposit webhook.
      required:
        - accountId
        - cryptoCurrencyCode
        - customerId
    AddressProvisionCreatedResponseDto:
      type: object
      properties:
        data:
          $ref: '#/components/schemas/AddressProvisionCreateDataDto'
      required:
        - data
    AddressProvisionGetResponseDto:
      type: object
      properties:
        data:
          $ref: '#/components/schemas/AddressProvisionGetDataDto'
      required:
        - data
    CreateInvoiceApiKeyRequestDto:
      type: object
      properties:
        accountId:
          type: string
          format: uuid
          description: >-
            Tenant account the invoice is billed to (must belong to your
            tenant). The merchant API key authenticates your tenant. Only this
            field selects the account for this request.
        amount:
          type: number
          description: >-
            Fiat amount charged by the invoice. Exactly one of `amount` or
            `items` must be provided.
          minimum: 0
          example: 49.99
        items:
          description: >-
            Line items charged by the invoice. The invoice total is the sum of
            `cost * quantity` across all items.
          type: array
          items:
            $ref: '#/components/schemas/InvoiceItemDto'
        fiatCurrencyCode:
          type: string
          description: ISO-4217 fiat currency code (e.g. `USD`, `EUR`).
          example: USD
        orderId:
          type: string
          description: >-
            Merchant-side idempotency key. Must be unique within your tenant.
            Retrying the request with the same `orderId` returns a 409.
          example: order_2026_04_001
          maxLength: 256
        description:
          type: string
          description: Free-form description shown on the payment page.
          maxLength: 512
        webhookUrl:
          type: string
          description: >-
            HTTPS URL to receive webhook notifications about this invoice. Must
            be a public, TLD-qualified HTTPS URL.
          example: https://merchant.example.com/webhooks/cryptonly
        returnUrl:
          type: string
          description: >-
            HTTP(S) URL for the "Return to merchant" CTA when the invoice is
            `cancelled` or `expired`. Accepts any http(s) URL, including local
            development hosts such as `http://localhost:8000/...`.
          example: https://merchant.example.com/orders/order_2026_04_001
          maxLength: 512
        successUrl:
          type: string
          description: >-
            HTTP(S) URL for the "Return to merchant" CTA when the invoice is
            `paid` or `overpaid`. Accepts any http(s) URL, including local
            development hosts such as `http://localhost:8000/...`.
          example: https://merchant.example.com/orders/order_2026_04_001/success
          maxLength: 512
        failedUrl:
          type: string
          description: >-
            HTTP(S) URL for the "Return to merchant" CTA when the invoice is
            `failed`, `suspended`, or `partially_paid`. Accepts any http(s) URL,
            including local development hosts such as
            `http://localhost:8000/...`.
          example: https://merchant.example.com/orders/order_2026_04_001/failed
          maxLength: 512
        expiresInMinutes:
          type: number
          description: >-
            Invoice expiry in minutes from creation. Clamped to a server-side
            maximum. Maximum is 30 days.
          minimum: 15
          maximum: 43200
        customerId:
          type: string
          description: Customer ID from your system.
          example: customer_1234567890
          maxLength: 52
        customPayload:
          type: string
          description: Custom payload to be sent to the webhook.
          example: '{"key1":"value1","key2":"value2"}'
          maxLength: 2048
        number:
          type: string
          maxLength: 256
          description: >-
            Optional reference shown to the customer on the payment page (e.g.
            order or invoice id). If empty - orderId is shown instead.
      required:
        - accountId
        - fiatCurrencyCode
        - orderId
    InvoiceCreatedResponseDto:
      type: object
      properties:
        data:
          description: Invoice data (same shape as GET /invoice).
          allOf:
            - $ref: '#/components/schemas/InvoiceCreatedDataDto'
      required:
        - data
    TenantApiKeyInvoiceDataResponseDto:
      type: object
      properties:
        data:
          $ref: '#/components/schemas/TenantApiKeyInvoiceResponseDto'
      required:
        - data
    InvoiceListResponseDto:
      type: object
      properties:
        total:
          type: number
          description: Total number of matching rows.
        page:
          type: number
          description: 1-indexed page number that was returned.
        limit:
          type: number
          description: Items per page that were returned.
        hasMore:
          type: boolean
          description: True if there is at least one more page after this one.
        data:
          type: array
          items:
            $ref: '#/components/schemas/TenantApiKeyInvoiceResponseDto'
      required:
        - total
        - page
        - limit
        - hasMore
        - data
    ZapierSubscribeRequestDto:
      type: object
      properties:
        event:
          type: string
          enum:
            - invoice.statusChanged
            - deposit.statusChanged
            - withdrawal.statusChanged
          example: invoice.statusChanged
        targetUrl:
          type: string
          description: Zapier REST Hook target URL from bundle.targetUrl
          example: https://hooks.zapier.com/hooks/catch/123456/abcdef/
      required:
        - event
        - targetUrl
    ZapierSubscribeResponseDto:
      type: object
      properties:
        id:
          type: string
          format: uuid
      required:
        - id
    TenantAccountDto:
      type: object
      properties:
        id:
          type: string
          format: uuid
        name:
          type: string
        createdAt:
          type: string
          description: Account creation time (ISO-8601).
      required:
        - id
        - name
        - createdAt
    MerchantCurrencyDto:
      type: object
      properties:
        code:
          type: string
          description: Currency code.
          example: USDT_TRC20
          enum:
            - USDT_TRC20
            - USDT_ERC20
            - USDT_BEP20
            - USDC_ERC20
            - USDC_BEP20
            - ETH
            - TRX
            - BNB
            - BTC
        name:
          type: string
          description: Human-readable currency name.
        network:
          type: string
          description: Blockchain network the currency lives on.
          enum:
            - Tron
            - Solana
            - Ethereum
            - BNB
            - BTC
        tokenType:
          type: string
          description: >-
            Token standard (ERC20, TRC20, BEP20, ...) for non-native assets.
            Omitted for chain-native coins.
          enum:
            - erc20
            - trc20
            - bep20
        decimalPlaces:
          type: number
          description: >-
            Number of decimal places. Use to format on-chain amounts for
            display.
        minDepositAmount:
          type: number
          description: >-
            Smallest accepted deposit amount in this currency. Deposits below
            this threshold may be rejected or absorbed as dust.
        minWithdrawalAmount:
          type: number
          description: Smallest accepted withdrawal amount in this currency.
        depositCommission:
          type: number
          description: >-
            Effective deposit commission for the authenticated tenant. Reflects
            the per-tenant override when configured, otherwise the system
            default.
          example: 0.005
        contractAddress:
          type: string
          description: >-
            Smart contract address for token currencies (`null` for native
            coins).
          nullable: true
        imageUrl:
          type: string
          description: Optional URL to a currency icon, suitable for UI display.
          nullable: true
        networkIconUrl:
          type: string
          description: >-
            Optional URL for the underlying chain / network icon (e.g. on
            multi-network stablecoin pickers).
          nullable: true
        addressMask:
          type: string
          description: >-
            Optional regex (as a string) merchants can run client-side to
            pre-validate destination addresses before calling `POST
            /withdrawal/quote`.
          nullable: true
      required:
        - code
        - name
        - network
        - decimalPlaces
        - minDepositAmount
        - minWithdrawalAmount
        - depositCommission
        - contractAddress
        - imageUrl
        - addressMask
    MerchantFiatCurrencyDto:
      type: object
      properties:
        code:
          type: string
          description: ISO 4217-style currency code, e.g. `USD`, `EUR`, `RUB`.
          example: USD
        name:
          type: string
          description: Human-readable currency name.
        decimalPlaces:
          type: number
          description: Decimal places to use when formatting amounts (e.g. `2` for USD).
        minInvoiceAmount:
          type: number
          description: >-
            Smallest invoice amount accepted in this currency on `POST
            /invoice`.
      required:
        - code
        - name
        - decimalPlaces
        - minInvoiceAmount
    WithdrawalQuoteResponseDto:
      type: object
      properties:
        quoteId:
          type: string
          description: Opaque quote id; submit to `POST /withdrawal/commit` to commit.
        orderId:
          type: string
          description: >-
            Echo of the merchant `orderId` supplied at quote time. The merchant
            should persist this against their order so support tickets and
            webhooks correlate cleanly.
        cryptoCurrencyCode:
          type: string
          description: Currency code.
          example: USDT_TRC20
          enum:
            - USDT_TRC20
            - USDT_ERC20
            - USDT_BEP20
            - USDC_ERC20
            - USDC_BEP20
            - ETH
            - TRX
            - BNB
            - BTC
        address:
          type: string
          description: Echo of `address`
        amount:
          type: number
          description: >-
            Echo of `amount` - denominated in `cryptoCurrencyCode` (this is what
            reaches the destination address).
        autoConvert:
          description: >-
            When present, a virtual conversion is locked to top up the
            withdrawal asset before the withdrawal debit. Commission is in
            `fromAssetCode`.
          nullable: true
          allOf:
            - $ref: '#/components/schemas/WithdrawalAutoConvertPreviewDto'
        totalDeduction:
          type: number
          description: >-
            Total to debit in `cryptoCurrencyCode` at commit (on-chain amount +
            on-chain fee component in the withdrawal asset).
        fee:
          $ref: '#/components/schemas/WithdrawalQuoteFeeBreakdownDto'
        expiresAt:
          type: string
          description: >-
            ISO timestamp after which the quote can no longer be committed.
            Re-issue a new quote if expired.
      required:
        - quoteId
        - orderId
        - cryptoCurrencyCode
        - address
        - amount
        - totalDeduction
        - fee
        - expiresAt
    WithdrawalDto:
      type: object
      properties:
        id:
          type: string
        orderId:
          type: string
        accountId:
          type: string
        cryptoCurrencyCode:
          type: string
          description: Currency code.
          example: USDT_TRC20
          enum:
            - USDT_TRC20
            - USDT_ERC20
            - USDT_BEP20
            - USDC_ERC20
            - USDC_BEP20
            - ETH
            - TRX
            - BNB
            - BTC
        address:
          type: string
          description: Destination wallet address
        transactionHash:
          type: string
          nullable: true
          description: On-chain transaction hash
        amount:
          type: number
          description: Withdrawal amount in `cryptoCurrencyCode`
        amountUsd:
          type: number
          description: Withdrawal amount in USD
        status:
          type: string
          enum:
            - created
            - processing
            - completed
            - failed
            - cancelled
        convertId:
          type: string
          nullable: true
          format: uuid
          description: >-
            Optional funding `currency_conversion` that topped up the withdrawal
            asset before this withdrawal debit (auto-convert).
        feeAmount:
          type: number
          description: >-
            Network fee debited from the user in `cryptoCurrencyCode` (same
            value used in `debitedAmount` = amount + this fee)
        feeAmountUsd:
          type: number
          description: Same fee, snapshotted to USD at commit time
        debitedAmount:
          type: number
          description: >-
            Exact total debited in `cryptoCurrencyCode` (on-chain amount +
            on-chain fee)
        customData:
          type: object
        webhookUrl:
          type: string
          nullable: true
        source:
          type: string
          enum:
            - api
            - admin_panel
          description: >-
            Commit channel; omitted when unknown (rows created before this
            metadata existed).
        createdAt:
          type: string
          description: ISO 8601 timestamp.
        updatedAt:
          type: string
          description: ISO 8601 timestamp.
        quoteId:
          type: string
          nullable: true
          format: uuid
          description: >-
            Opaque id from the quote phase; equals the committed network
            transfer id when set.
        transferId:
          type: string
          nullable: true
          format: uuid
          description: Network transfer backing this withdrawal once committed.
      required:
        - id
        - orderId
        - accountId
        - cryptoCurrencyCode
        - address
        - amount
        - amountUsd
        - status
        - feeAmount
        - feeAmountUsd
        - debitedAmount
        - createdAt
        - updatedAt
        - quoteId
        - transferId
    InvoiceStatusChangedWebhookDataDto:
      type: object
      properties:
        id:
          type: string
        accountId:
          type: string
          format: uuid
        orderId:
          type: string
        amount:
          type: number
        fiatCurrencyCode:
          type: string
        items:
          type: array
          items:
            $ref: '#/components/schemas/InvoiceItemDto'
        status:
          type: string
          enum:
            - created
            - processing
            - paid
            - partially_paid
            - overpaid
            - expired
            - cancelled
            - failed
            - suspended
        cryptoCurrencyCode:
          type: string
          enum:
            - USDT_TRC20
            - USDT_ERC20
            - USDT_BEP20
            - USDC_ERC20
            - USDC_BEP20
            - ETH
            - TRX
            - BNB
            - BTC
          example: USDT_TRC20
        cryptoAmountExpected:
          type: number
        cryptoAmountReceived:
          type: number
        address:
          type: string
        txHash:
          type: string
        settlement:
          $ref: '#/components/schemas/SettlementBreakdownDto'
        description:
          type: string
        number:
          type: string
          maxLength: 256
          description: >-
            Optional reference for the customer on the payment page, when set at
            creation.
        webhookUrl:
          type: string
        returnUrl:
          type: string
          description: >-
            Browser CTA URL for `cancelled` / `expired`, when provided at
            creation.
        successUrl:
          type: string
          description: Browser CTA URL for `paid` / `overpaid`, when provided at creation.
        failedUrl:
          type: string
          description: >-
            Browser CTA URL for `failed` / `suspended` / `partially_paid`, when
            provided at creation.
        expiresAt:
          type: string
          description: ISO 8601 timestamp.
        createdAt:
          type: string
          description: ISO 8601 timestamp.
        paidAt:
          type: string
          description: When payment settled (ISO 8601), if applicable.
        customerId:
          type: string
          description: Merchant-supplied customer reference when provided at creation.
        customPayload:
          type: string
          description: Opaque string from creation; echoed on webhooks when set.
        paymentPageUrl:
          type: string
          description: Hosted payment page URL for this invoice.
          example: https://payment.cryptonly.com/invoice/...
        source:
          type: string
          enum:
            - api
            - admin_panel
          description: >-
            Creation channel; omitted when unknown (rows created before this
            metadata existed).
        previousStatus:
          type: string
          enum:
            - created
            - processing
            - paid
            - partially_paid
            - overpaid
            - expired
            - cancelled
            - failed
            - suspended
          description: Status immediately before this transition.
      required:
        - id
        - accountId
        - amount
        - fiatCurrencyCode
        - items
        - status
        - expiresAt
        - createdAt
        - paymentPageUrl
    DepositStatusChangedWebhookDataDto:
      type: object
      properties:
        id:
          type: string
        accountId:
          type: string
          format: uuid
        orderId:
          type: string
        customerId:
          type: string
        status:
          type: string
          enum:
            - created
            - processing
            - completed
            - suspended
            - failed
            - expired
            - cancelled
        cryptoCurrencyCode:
          type: string
          enum:
            - USDT_TRC20
            - USDT_ERC20
            - USDT_BEP20
            - USDC_ERC20
            - USDC_BEP20
            - ETH
            - TRX
            - BNB
            - BTC
          example: USDT_TRC20
        address:
          type: string
        expiresAt:
          type: string
        createdAt:
          type: string
        updatedAt:
          type: string
        settlement:
          $ref: '#/components/schemas/SettlementBreakdownDto'
        previousStatus:
          type: string
          enum:
            - created
            - processing
            - completed
            - suspended
            - failed
            - expired
            - cancelled
          description: Status immediately before this transition.
        addressProvisionId:
          type: string
          format: uuid
          description: >-
            Present when this deposit is a payment under an address provision
            session.
        depositTransactionHash:
          type: string
          nullable: true
        actuallyReceivedAmount:
          type: number
          nullable: true
        actuallyReceivedAmountUsd:
          type: number
          nullable: true
      required:
        - id
        - accountId
        - status
        - cryptoCurrencyCode
        - expiresAt
        - createdAt
        - updatedAt
    WithdrawalStatusChangedWebhookDataDto:
      type: object
      properties:
        id:
          type: string
        orderId:
          type: string
        accountId:
          type: string
        cryptoCurrencyCode:
          type: string
          description: Currency code.
          example: USDT_TRC20
          enum:
            - USDT_TRC20
            - USDT_ERC20
            - USDT_BEP20
            - USDC_ERC20
            - USDC_BEP20
            - ETH
            - TRX
            - BNB
            - BTC
        address:
          type: string
          description: Destination wallet address
        transactionHash:
          type: string
          nullable: true
          description: On-chain transaction hash
        amount:
          type: number
          description: Withdrawal amount in `cryptoCurrencyCode`
        amountUsd:
          type: number
          description: Withdrawal amount in USD
        status:
          type: string
          enum:
            - created
            - processing
            - completed
            - failed
            - cancelled
        convertId:
          type: string
          nullable: true
          format: uuid
          description: >-
            Optional funding `currency_conversion` that topped up the withdrawal
            asset before this withdrawal debit (auto-convert).
        feeAmount:
          type: number
          description: >-
            Network fee debited from the user in `cryptoCurrencyCode` (same
            value used in `debitedAmount` = amount + this fee)
        feeAmountUsd:
          type: number
          description: Same fee, snapshotted to USD at commit time
        debitedAmount:
          type: number
          description: >-
            Exact total debited in `cryptoCurrencyCode` (on-chain amount +
            on-chain fee)
        customData:
          type: object
        webhookUrl:
          type: string
          nullable: true
        source:
          type: string
          enum:
            - api
            - admin_panel
          description: >-
            Commit channel; omitted when unknown (rows created before this
            metadata existed).
        createdAt:
          type: string
          description: ISO 8601 timestamp.
        updatedAt:
          type: string
          description: ISO 8601 timestamp.
        quoteId:
          type: string
          nullable: true
          format: uuid
          description: >-
            Opaque id from the quote phase; equals the committed network
            transfer id when set.
        transferId:
          type: string
          nullable: true
          format: uuid
          description: Network transfer backing this withdrawal once committed.
        previousStatus:
          type: string
          enum:
            - created
            - processing
            - completed
            - failed
            - cancelled
          description: Status immediately before this transition.
      required:
        - id
        - orderId
        - accountId
        - cryptoCurrencyCode
        - address
        - amount
        - amountUsd
        - status
        - feeAmount
        - feeAmountUsd
        - debitedAmount
        - createdAt
        - updatedAt
        - quoteId
        - transferId
    DepositCreateDataDto:
      type: object
      properties:
        id:
          type: string
          format: uuid
        minimumAmount:
          type: number
        address:
          type: string
        createdAt:
          type: string
          description: ISO 8601 — when the deposit address window started.
        expiresAt:
          type: string
          description: ISO 8601 expiry for the deposit address.
        qrCode:
          type: string
          description: PNG QR code as a data URL (data:image/png;base64,...).
      required:
        - id
        - minimumAmount
        - address
        - createdAt
        - expiresAt
        - qrCode
    TenantApiKeyDepositResponseDto:
      type: object
      properties:
        id:
          type: string
        accountId:
          type: string
          format: uuid
        orderId:
          type: string
        customerId:
          type: string
        status:
          type: string
          enum:
            - created
            - processing
            - completed
            - suspended
            - failed
            - expired
            - cancelled
        cryptoCurrencyCode:
          type: string
          enum:
            - USDT_TRC20
            - USDT_ERC20
            - USDT_BEP20
            - USDC_ERC20
            - USDC_BEP20
            - ETH
            - TRX
            - BNB
            - BTC
          example: USDT_TRC20
        address:
          type: string
        expiresAt:
          type: string
        createdAt:
          type: string
        updatedAt:
          type: string
        settlement:
          $ref: '#/components/schemas/SettlementBreakdownDto'
      required:
        - id
        - accountId
        - status
        - cryptoCurrencyCode
        - expiresAt
        - createdAt
        - updatedAt
    AddressProvisionCreateDataDto:
      type: object
      properties:
        id:
          type: string
          format: uuid
        minimumAmount:
          type: number
        address:
          type: string
        createdAt:
          type: string
          description: ISO 8601 — when the provision window started.
        expiresAt:
          type: string
          description: ISO 8601 expiry for the deposit address.
        qrCode:
          type: string
          description: PNG QR code as a data URL (data:image/png;base64,...).
      required:
        - id
        - minimumAmount
        - address
        - createdAt
        - expiresAt
        - qrCode
    AddressProvisionGetDataDto:
      type: object
      properties:
        id:
          type: string
          format: uuid
        minimumAmount:
          type: number
        address:
          type: string
        createdAt:
          type: string
          description: ISO 8601 — when the provision window started.
        expiresAt:
          type: string
          description: ISO 8601 expiry for the deposit address.
        qrCode:
          type: string
          description: PNG QR code as a data URL (data:image/png;base64,...).
        status:
          type: string
          enum:
            - active
            - expired
            - closed
        customerId:
          type: string
      required:
        - id
        - minimumAmount
        - address
        - createdAt
        - expiresAt
        - qrCode
        - status
        - customerId
    InvoiceItemDto:
      type: object
      properties:
        name:
          type: string
        quantity:
          type: number
        cost:
          type: number
      required:
        - name
        - quantity
        - cost
    InvoiceCreatedDataDto:
      type: object
      properties:
        id:
          type: string
        accountId:
          type: string
          format: uuid
        orderId:
          type: string
        amount:
          type: number
        fiatCurrencyCode:
          type: string
        items:
          type: array
          items:
            $ref: '#/components/schemas/InvoiceItemDto'
        status:
          type: string
          enum:
            - created
            - processing
            - paid
            - partially_paid
            - overpaid
            - expired
            - cancelled
            - failed
            - suspended
        cryptoCurrencyCode:
          type: string
          enum:
            - USDT_TRC20
            - USDT_ERC20
            - USDT_BEP20
            - USDC_ERC20
            - USDC_BEP20
            - ETH
            - TRX
            - BNB
            - BTC
          example: USDT_TRC20
        cryptoAmountExpected:
          type: number
        cryptoAmountReceived:
          type: number
        address:
          type: string
        txHash:
          type: string
        settlement:
          $ref: '#/components/schemas/SettlementBreakdownDto'
        description:
          type: string
        number:
          type: string
          maxLength: 256
          description: >-
            Optional reference for the customer on the payment page, when set at
            creation.
        webhookUrl:
          type: string
        returnUrl:
          type: string
          description: >-
            Browser CTA URL for `cancelled` / `expired`, when provided at
            creation.
        successUrl:
          type: string
          description: Browser CTA URL for `paid` / `overpaid`, when provided at creation.
        failedUrl:
          type: string
          description: >-
            Browser CTA URL for `failed` / `suspended` / `partially_paid`, when
            provided at creation.
        expiresAt:
          type: string
          description: ISO 8601 timestamp.
        createdAt:
          type: string
          description: ISO 8601 timestamp.
        paidAt:
          type: string
          description: When payment settled (ISO 8601), if applicable.
        customerId:
          type: string
          description: Merchant-supplied customer reference when provided at creation.
        customPayload:
          type: string
          description: Opaque string from creation; echoed on webhooks when set.
        paymentPageUrl:
          type: string
          description: Hosted payment page URL for this invoice.
          example: https://payment.cryptonly.com/invoice/...
        source:
          type: string
          enum:
            - api
            - admin_panel
          description: >-
            Creation channel; omitted when unknown (rows created before this
            metadata existed).
      required:
        - id
        - accountId
        - amount
        - fiatCurrencyCode
        - items
        - status
        - expiresAt
        - createdAt
        - paymentPageUrl
    TenantApiKeyInvoiceResponseDto:
      type: object
      properties:
        id:
          type: string
        accountId:
          type: string
          format: uuid
        orderId:
          type: string
        amount:
          type: number
        fiatCurrencyCode:
          type: string
        items:
          type: array
          items:
            $ref: '#/components/schemas/InvoiceItemDto'
        status:
          type: string
          enum:
            - created
            - processing
            - paid
            - partially_paid
            - overpaid
            - expired
            - cancelled
            - failed
            - suspended
        cryptoCurrencyCode:
          type: string
          enum:
            - USDT_TRC20
            - USDT_ERC20
            - USDT_BEP20
            - USDC_ERC20
            - USDC_BEP20
            - ETH
            - TRX
            - BNB
            - BTC
          example: USDT_TRC20
        cryptoAmountExpected:
          type: number
        cryptoAmountReceived:
          type: number
        address:
          type: string
        txHash:
          type: string
        settlement:
          $ref: '#/components/schemas/SettlementBreakdownDto'
        description:
          type: string
        number:
          type: string
          maxLength: 256
          description: >-
            Optional reference for the customer on the payment page, when set at
            creation.
        webhookUrl:
          type: string
        returnUrl:
          type: string
          description: >-
            Browser CTA URL for `cancelled` / `expired`, when provided at
            creation.
        successUrl:
          type: string
          description: Browser CTA URL for `paid` / `overpaid`, when provided at creation.
        failedUrl:
          type: string
          description: >-
            Browser CTA URL for `failed` / `suspended` / `partially_paid`, when
            provided at creation.
        expiresAt:
          type: string
          description: ISO 8601 timestamp.
        createdAt:
          type: string
          description: ISO 8601 timestamp.
        paidAt:
          type: string
          description: When payment settled (ISO 8601), if applicable.
        customerId:
          type: string
          description: Merchant-supplied customer reference when provided at creation.
        customPayload:
          type: string
          description: Opaque string from creation; echoed on webhooks when set.
        paymentPageUrl:
          type: string
          description: Hosted payment page URL for this invoice.
          example: https://payment.cryptonly.com/invoice/...
        source:
          type: string
          enum:
            - api
            - admin_panel
          description: >-
            Creation channel; omitted when unknown (rows created before this
            metadata existed).
      required:
        - id
        - accountId
        - amount
        - fiatCurrencyCode
        - items
        - status
        - expiresAt
        - createdAt
        - paymentPageUrl
    WithdrawalAutoConvertPreviewDto:
      type: object
      properties:
        fromAssetCode:
          type: string
          description: Asset code.
          example: USDT
          enum:
            - USDT
            - USDC
            - ETH
            - TRX
            - BNB
            - BTC
        toAssetCode:
          type: string
          description: Asset code.
          example: USDT
          enum:
            - USDT
            - USDC
            - ETH
            - TRX
            - BNB
            - BTC
        fromAmount:
          type: number
        toAmount:
          type: number
      required:
        - fromAssetCode
        - toAssetCode
        - fromAmount
        - toAmount
    WithdrawalQuoteFeeBreakdownDto:
      type: object
      properties:
        feeNative:
          type: number
          description: Real on-chain fee, in network base currency (e.g. ETH/TRX/BNB/BTC)
        feeCurrency:
          type: string
          description: Network base currency symbol
        feeInCryptoCurrencyCode:
          type: number
          description: >-
            On-chain fee at quote time, expressed in the withdrawal
            `cryptoCurrencyCode`.
        feeUsd:
          type: number
          description: Fee snapshotted to USD at quote time
      required:
        - feeNative
        - feeCurrency
        - feeInCryptoCurrencyCode
        - feeUsd
    SettlementBreakdownDto:
      type: object
      properties:
        amountPaid:
          type: number
        amountPaidUsd:
          type: number
        commissionAmount:
          type: number
        commissionAmountUsd:
          type: number
        networkFeeAmount:
          type: number
        networkFeeAmountUsd:
          type: number
        networkFeeCurrencyCode:
          type: string
        netAmount:
          type: number
        netAmountUsd:
          type: number
        txHash:
          type: string
        completedAt:
          type: string
      required:
        - amountPaid
        - amountPaidUsd
        - commissionAmount
        - commissionAmountUsd
        - networkFeeAmount
        - networkFeeAmountUsd
        - networkFeeCurrencyCode
        - netAmount
        - netAmountUsd
        - completedAt
security:
  - TENANT_API_KEY: []
