{
  "openapi": "3.1.0",
  "jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
  "info": {
    "title": "CoinsSend Public API",
    "version": "1.0.0",
    "summary": "Verified merchant integration and public checkout contract",
    "description": "This document is an explicit allowlist verified against the application routes, controllers, requests, resources, middleware, and webhook formatter. It intentionally excludes dashboard, internal, provider-callback, paywall, and undocumented payment-page operations. Runtime-owned asset values are discovered through the catalog endpoints and are not frozen as enums.",
    "contact": {
      "name": "CoinsSend Support",
      "url": "https://coinssend.com"
    },
    "x-contract-scope": "verified-public-allowlist",
    "x-signature-test-vectors": "./signature-test-vectors.json",
    "x-runtime-owned": [
      "asset and network availability",
      "asset decimals and amount limits",
      "rates and fees",
      "provider-card capability",
      "edge rate limiting",
      "webhook transport retry policy"
    ]
  },
  "servers": [
    {
      "url": "https://api.coinssend.com",
      "description": "Production"
    }
  ],
  "tags": [
    {
      "name": "Invoices",
      "description": "Merchant invoice creation and public checkout state."
    },
    {
      "name": "Withdrawals",
      "description": "Timestamp-signed merchant withdrawals."
    },
    {
      "name": "Merchant",
      "description": "Signed merchant balance and fee discovery."
    },
    {
      "name": "Wallets",
      "description": "Static or merchant wallet creation and public QR rendering."
    },
    {
      "name": "Catalog",
      "description": "Public runtime rate and asset metadata."
    },
    {
      "name": "Provider card",
      "description": "Public checkout operation for an invoice that opted into card payments."
    }
  ],
  "paths": {
    "/v1/invoices": {
      "post": {
        "operationId": "createInvoice",
        "tags": ["Invoices"],
        "summary": "Create an invoice",
        "description": "Creates a new invoice. A merchant-scoped order_id must be unique. Repeating an already accepted order_id returns 409; it does not replay the original response.",
        "security": [
          {
            "MerchantHeader": [],
            "SignatureHeader": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OptionalTimestamp"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/InvoiceCreateRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Invoice created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InvoiceCreateResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "description": "The order_id already exists for this merchant.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ControllerError"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "x-signature-mode": "legacy-md5-or-optional-timestamped-hmac",
        "x-idempotency": "none; order_id uniqueness returns 409"
      }
    },
    "/v1/invoices/{invoiceCode}": {
      "get": {
        "operationId": "getInvoice",
        "tags": ["Invoices"],
        "summary": "Get public invoice checkout state",
        "description": "No merchant authentication is required. Treat invoiceCode as a public checkout identifier, not as authorization to other merchant resources.",
        "parameters": [
          {
            "$ref": "#/components/parameters/InvoiceCode"
          }
        ],
        "responses": {
          "200": {
            "description": "Current invoice state and runtime payment options.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InvoiceShowResponse"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/v1/invoices/{invoiceCode}/provider-card-orders": {
      "post": {
        "operationId": "createProviderCardOrder",
        "tags": ["Provider card"],
        "summary": "Start or reuse an active provider-card checkout",
        "description": "The API owns the provider and payout pair. The current internal pair is usdc on polygon; provider-specific aliases are implementation details. Provider, coin, and network request fields are not part of this contract. Availability depends on invoice state, feature configuration, provider capability, and the configured hot wallet.",
        "parameters": [
          {
            "$ref": "#/components/parameters/InvoiceCode"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ProviderCardOrderCreateRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Order created or an active order reused.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProviderCardOrderCreateResponse"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "description": "Invalid email validation, or checkout is not allowed or unavailable. Capability/state failures include failure_code; validation failures use the validation envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/ValidationError"
                    },
                    {
                      "$ref": "#/components/schemas/ProviderCardError"
                    }
                  ]
                }
              }
            }
          },
          "502": {
            "description": "The provider could not create a usable checkout.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProviderCardError"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "x-runtime-owned": true,
        "x-runtime-owner": "ProviderCardCapabilityGate and provider adapter configuration",
        "x-idempotency": "active-order-reuse-only; no Idempotency-Key contract"
      }
    },
    "/v1/withdrawals": {
      "post": {
        "operationId": "createWithdrawal",
        "tags": ["Withdrawals"],
        "summary": "Submit a withdrawal",
        "description": "Submits an asynchronous withdrawal command but returns HTTP 200 when accepted. Timestamp freshness is replay mitigation, not idempotency. Do not automatically repeat a request after an unknown outcome.",
        "security": [
          {
            "MerchantHeader": [],
            "SignatureHeader": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/RequiredTimestamp"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WithdrawalRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Withdrawal command accepted. The returned status is the current projected state, not final settlement.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WithdrawalResponse"
                }
              }
            }
          },
          "400": {
            "description": "Missing auth headers/timestamp, permission denial, insufficient balance, or another service-level rejection. Middleware and controller errors have different shapes.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/AuthError"
                    },
                    {
                      "$ref": "#/components/schemas/ControllerError"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "x-signature-mode": "required-timestamped-hmac",
        "x-signature-window-seconds": 300,
        "x-idempotency": "none"
      }
    },
    "/v1/merchants/balances": {
      "get": {
        "operationId": "getMerchantBalances",
        "tags": ["Merchant"],
        "summary": "Get merchant balances",
        "description": "Returns the merchant's current balances, frozen amounts, available amounts, and runtime USD valuations for visible asset/network pairs.",
        "security": [
          {
            "MerchantHeader": [],
            "SignatureHeader": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OptionalTimestamp"
          }
        ],
        "responses": {
          "200": {
            "description": "Current balances and USD valuation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MerchantBalancesResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "x-runtime-owned": true,
        "x-runtime-owner": "merchant balances, CryptoCoinConfig, and CoinRate"
      }
    },
    "/v1/merchants/fees": {
      "get": {
        "operationId": "getMerchantFees",
        "tags": ["Merchant"],
        "summary": "Get merchant fee settings",
        "description": "Returns merchant-specific fee percentages, fee-payer settings, auto-exchange settings, and runtime network fees.",
        "security": [
          {
            "MerchantHeader": [],
            "SignatureHeader": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OptionalTimestamp"
          }
        ],
        "responses": {
          "200": {
            "description": "Current merchant-specific fee settings.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MerchantFeesResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "x-runtime-owned": true,
        "x-runtime-owner": "merchant API-key settings and CryptoCoinConfig"
      }
    },
    "/v1/wallet-address": {
      "post": {
        "operationId": "createWalletAddress",
        "tags": ["Wallets"],
        "summary": "Create a wallet address",
        "description": "Creates a static wallet by default. Repeating a static-wallet request creates another wallet if the first request succeeded. Merchant-type wallets have a separate one-per-pair guard, but there is no request replay contract.",
        "security": [
          {
            "MerchantHeader": [],
            "SignatureHeader": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/OptionalTimestamp"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WalletAddressCreateRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Wallet address created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WalletAddressCreateResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "description": "Wallet creation is already in progress.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ControllerError"
                }
              }
            }
          },
          "422": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "x-runtime-owned": true,
        "x-runtime-owner": "CreateMerchantWalletRequest, CryptoCoinConfig decimals lookup, wallet creator, and merchant-scoped lock",
        "x-idempotency": "none for static wallets"
      }
    },
    "/v1/wallet-addresses/{walletAddress}/qr": {
      "get": {
        "operationId": "getWalletQrCode",
        "tags": ["Wallets"],
        "summary": "Render a wallet QR code",
        "description": "The path value is the wallet record identifier embedded in qr_code_url responses, despite the historical parameter name walletAddress.",
        "parameters": [
          {
            "name": "walletAddress",
            "in": "path",
            "required": true,
            "description": "Wallet record identifier returned in qr_code_url.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "PNG image.",
            "content": {
              "image/png": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/v1/get-coin-rate": {
      "get": {
        "operationId": "getCoinRates",
        "tags": ["Catalog"],
        "summary": "Get public rates and network metadata",
        "description": "Returns visible runtime asset rates, derived quotes, and per-network deposit and withdrawal metadata. Values can change without a schema version change.",
        "responses": {
          "200": {
            "description": "Runtime rate and network metadata.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CoinRateResponse"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "x-runtime-owned": true,
        "x-runtime-owner": "CryptoCoinConfig and CoinRate"
      }
    },
    "/v1/coins-and-fee": {
      "get": {
        "operationId": "getCoinCatalog",
        "tags": ["Catalog"],
        "summary": "Get the enabled asset catalog",
        "description": "Use this endpoint for runtime discovery. It excludes hidden pairs and pairs with both deposit and withdrawal disabled. Individual write endpoints remain the final authority for accepting a pair.",
        "responses": {
          "200": {
            "description": "Enabled asset catalog.",
            "headers": {
              "Cache-Control": {
                "description": "The application route currently advertises a 900-second public cache lifetime.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CoinCatalogResponse"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "x-runtime-owned": true,
        "x-runtime-owner": "CoinCatalogService backed by CryptoCoinConfig and runtime configuration",
        "x-cache-seconds": 900
      }
    }
  },
  "webhooks": {
    "merchantEvent": {
      "post": {
        "operationId": "receiveCoinsSendWebhook",
        "summary": "Receive a signed CoinsSend event",
        "description": "CoinsSend POSTs to the merchant-configured callback URL. Verify X-Signature over the exact raw request body before parsing JSON. Respond with a 2xx status. Duplicate delivery is possible. The exact transport retry schedule is runtime-owned and is not promised here.",
        "parameters": [
          {
            "name": "X-Signature",
            "in": "header",
            "required": true,
            "description": "Lowercase hexadecimal HMAC-SHA256 of the exact raw body, using the merchant API key as secret.",
            "schema": {
              "type": "string",
              "pattern": "^[a-f0-9]{64}$"
            }
          },
          {
            "name": "X-Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Currently supplied with withdrawal events as withdrawal:{withdrawal_id}:{event}. It is not guaranteed for invoice, wallet, AML, or test events.",
            "schema": {
              "type": "string"
            },
            "x-events": [
              "withdrawal.in_progress",
              "withdrawal.success",
              "withdrawal.failed"
            ]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "oneOf": [
                  {
                    "$ref": "#/components/schemas/InvoiceWebhook"
                  },
                  {
                    "$ref": "#/components/schemas/WalletTransactionWebhook"
                  },
                  {
                    "$ref": "#/components/schemas/WithdrawalWebhook"
                  },
                  {
                    "$ref": "#/components/schemas/AmlRejectedWebhook"
                  },
                  {
                    "$ref": "#/components/schemas/TestWebhook"
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Acknowledged. Keep the handler fast and process asynchronously where possible."
          },
          "default": {
            "description": "A non-2xx response is not an acknowledgement and may lead to another delivery."
          }
        },
        "x-runtime-owned": true,
        "x-runtime-owner": "WebhookPayloadFormatter, WebhookService, queue consumer, and external delivery worker",
        "x-retry-policy": "not statically guaranteed"
      }
    }
  },
  "components": {
    "securitySchemes": {
      "MerchantHeader": {
        "type": "apiKey",
        "in": "header",
        "name": "Merchant",
        "description": "Merchant identifier."
      },
      "SignatureHeader": {
        "type": "apiKey",
        "in": "header",
        "name": "Sign",
        "description": "Request signature computed from the server-canonical JSON payload. See authentication.md and signature-test-vectors.json."
      }
    },
    "parameters": {
      "InvoiceCode": {
        "name": "invoiceCode",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string",
          "minLength": 1
        }
      },
      "OptionalTimestamp": {
        "name": "Timestamp",
        "in": "header",
        "required": false,
        "description": "When supplied, it must be a Unix timestamp within 300 seconds of server time and Sign must use timestamped HMAC-SHA256. X-Timestamp is accepted as an alias. Omit it to use the legacy MD5 signature on this operation.",
        "schema": {
          "type": "string",
          "pattern": "^[0-9]+$"
        }
      },
      "RequiredTimestamp": {
        "name": "Timestamp",
        "in": "header",
        "required": true,
        "description": "Unix timestamp in seconds, within 300 seconds of server time. X-Timestamp is accepted as an alias.",
        "schema": {
          "type": "string",
          "pattern": "^[0-9]+$"
        }
      }
    },
    "responses": {
      "BadRequest": {
        "description": "Bad request. Header-auth failures use the AuthError shape; controller failures use ControllerError.",
        "content": {
          "application/json": {
            "schema": {
              "oneOf": [
                {
                  "$ref": "#/components/schemas/AuthError"
                },
                {
                  "$ref": "#/components/schemas/ControllerError"
                }
              ]
            }
          }
        }
      },
      "Unauthorized": {
        "description": "Invalid merchant, signature, or timestamp. Header-auth failures use AuthError.",
        "content": {
          "application/json": {
            "schema": {
              "oneOf": [
                {
                  "$ref": "#/components/schemas/AuthError"
                },
                {
                  "$ref": "#/components/schemas/ControllerError"
                }
              ]
            }
          }
        }
      },
      "Forbidden": {
        "description": "The merchant is suspended or the operation is blocked for the merchant status.",
        "content": {
          "application/json": {
            "schema": {
              "oneOf": [
                {
                  "$ref": "#/components/schemas/AuthError"
                },
                {
                  "$ref": "#/components/schemas/ControllerError"
                }
              ]
            }
          }
        }
      },
      "NotFound": {
        "description": "Resource not found.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ControllerError"
            }
          }
        }
      },
      "ValidationFailed": {
        "description": "Request validation failed.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ValidationError"
            }
          }
        }
      },
      "TooManyRequests": {
        "description": "The application or deployment edge rejected the request. Retry-After and a single envelope are not guaranteed.",
        "content": {
          "application/json": {
            "schema": {
              "oneOf": [
                {
                  "$ref": "#/components/schemas/ControllerError"
                },
                {
                  "$ref": "#/components/schemas/ThrottleError"
                }
              ]
            }
          }
        },
        "x-runtime-owned": true
      },
      "InternalError": {
        "description": "Internal server error.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ControllerError"
            }
          }
        }
      }
    },
    "schemas": {
      "AssetCode": {
        "type": "string",
        "minLength": 1,
        "description": "Runtime-owned asset identifier. Discover current values through /v1/coins-and-fee; do not hard-code this as a closed enum.",
        "examples": ["usdt"],
        "x-runtime-owned": true
      },
      "NetworkCode": {
        "type": "string",
        "minLength": 1,
        "description": "Runtime-owned network identifier. Discover current values through /v1/coins-and-fee; write endpoints remain the final validation authority.",
        "examples": ["tron"],
        "x-runtime-owned": true
      },
      "NonNegativeDecimalString": {
        "type": "string",
        "pattern": "^[0-9]+(?:\\.[0-9]+)?$",
        "examples": ["10.50"]
      },
      "AuthError": {
        "type": "object",
        "required": ["error"],
        "properties": {
          "error": {
            "type": "string",
            "examples": ["Invalid sign"]
          }
        },
        "additionalProperties": false
      },
      "ControllerError": {
        "type": "object",
        "required": ["status", "message"],
        "properties": {
          "status": {
            "const": "error"
          },
          "message": {
            "type": "string"
          },
          "trace": {
            "description": "Non-production diagnostic field; not present in production."
          }
        },
        "additionalProperties": true
      },
      "ValidationError": {
        "type": "object",
        "required": ["errors", "status", "message"],
        "properties": {
          "errors": {
            "type": "object",
            "additionalProperties": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          "status": {
            "const": "error"
          },
          "message": {
            "type": "string"
          },
          "trace": {
            "description": "Non-production diagnostic field; not present in production."
          }
        },
        "additionalProperties": true
      },
      "ThrottleError": {
        "type": "object",
        "required": ["status", "message"],
        "properties": {
          "status": {
            "const": "error"
          },
          "message": {
            "type": "string"
          },
          "retry_after": {
            "type": "integer",
            "minimum": 0
          }
        },
        "additionalProperties": true
      },
      "InvoiceCreateRequest": {
        "type": "object",
        "required": ["order_id", "amount"],
        "properties": {
          "order_id": {
            "type": "string",
            "minLength": 1
          },
          "amount": {
            "$ref": "#/components/schemas/NonNegativeDecimalString",
            "description": "Invoice amount in USD. Runtime validation currently requires at least 3."
          },
          "is_customer_fee": {
            "type": "boolean",
            "default": false
          },
          "is_customer_network_fee": {
            "type": "boolean",
            "default": false
          },
          "allow_card_payments": {
            "type": "boolean",
            "default": false
          },
          "success_url": {
            "type": ["string", "null"],
            "format": "uri"
          },
          "cancel_url": {
            "type": ["string", "null"],
            "format": "uri"
          },
          "allowed_coins": {
            "type": ["array", "null"],
            "items": {
              "$ref": "#/components/schemas/AssetCode"
            },
            "description": "An empty array is normalized to null (all runtime-available coins).",
            "x-runtime-owned": true
          },
          "coin": {
            "$ref": "#/components/schemas/AssetCode"
          },
          "network": {
            "$ref": "#/components/schemas/NetworkCode"
          }
        },
        "dependentRequired": {
          "coin": ["network"],
          "network": ["coin"]
        }
      },
      "InvoiceCreateData": {
        "type": "object",
        "required": ["id", "order_id", "url", "code", "amount", "payer_amount", "expired_at", "created_at"],
        "properties": {
          "id": {
            "type": "string"
          },
          "order_id": {
            "type": "string"
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "code": {
            "type": "string"
          },
          "amount": {
            "$ref": "#/components/schemas/NonNegativeDecimalString"
          },
          "payer_amount": {
            "$ref": "#/components/schemas/NonNegativeDecimalString"
          },
          "expired_at": {
            "type": "string",
            "format": "date-time"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "InvoiceCreateResponse": {
        "type": "object",
        "required": ["data", "status"],
        "properties": {
          "data": {
            "$ref": "#/components/schemas/InvoiceCreateData"
          },
          "status": {
            "const": "success"
          }
        }
      },
      "InvoiceShowResponse": {
        "type": "object",
        "required": ["data", "status"],
        "properties": {
          "data": {
            "type": "object",
            "required": ["invoice", "network_fees"],
            "properties": {
              "invoice": {
                "$ref": "#/components/schemas/Invoice"
              },
              "network_fees": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": true
                },
                "x-runtime-owned": true
              }
            }
          },
          "status": {
            "const": "success"
          }
        }
      },
      "Invoice": {
        "type": "object",
        "required": [
          "id",
          "code",
          "url",
          "order_id",
          "merchant_name",
          "amount_usd",
          "payed_usd",
          "payer_amount_usd",
          "full_amount_usd",
          "amount_crypto",
          "payed_crypto",
          "fee_crypto",
          "network_fee_crypto",
          "payer_amount_crypto",
          "is_customer_fee",
          "is_customer_network_fee",
          "allow_card_payments",
          "wallet_address",
          "qr_code_url",
          "coin",
          "network",
          "status",
          "transaction_list",
          "allowed_coins",
          "allowed_networks",
          "provider_card",
          "created_at"
        ],
        "properties": {
          "id": {"type": "string"},
          "code": {"type": "string"},
          "url": {"type": "string", "format": "uri"},
          "order_id": {"type": "string"},
          "merchant_name": {"type": "string"},
          "amount_usd": {"$ref": "#/components/schemas/NonNegativeDecimalString"},
          "payed_usd": {"$ref": "#/components/schemas/NonNegativeDecimalString"},
          "payer_amount_usd": {"$ref": "#/components/schemas/NonNegativeDecimalString"},
          "full_amount_usd": {"$ref": "#/components/schemas/NonNegativeDecimalString"},
          "amount_crypto": {"$ref": "#/components/schemas/NonNegativeDecimalString"},
          "payed_crypto": {"$ref": "#/components/schemas/NonNegativeDecimalString"},
          "fee_crypto": {"$ref": "#/components/schemas/NonNegativeDecimalString"},
          "network_fee_crypto": {"$ref": "#/components/schemas/NonNegativeDecimalString"},
          "payer_amount_crypto": {"$ref": "#/components/schemas/NonNegativeDecimalString"},
          "amount_crypto_units": {"type": ["string", "null"]},
          "payed_crypto_units": {"type": ["string", "null"]},
          "fee_crypto_units": {"type": ["string", "null"]},
          "network_fee_crypto_units": {"type": ["string", "null"]},
          "payer_amount_crypto_units": {"type": ["string", "null"]},
          "is_customer_fee": {"type": "boolean"},
          "is_customer_network_fee": {"type": "boolean"},
          "allow_card_payments": {"type": "boolean"},
          "full_crypto_amount": {"type": ["string", "null"]},
          "wallet_address": {"type": ["string", "null"]},
          "qr_code_url": {"type": ["string", "null"], "format": "uri"},
          "coin": {"oneOf": [{"$ref": "#/components/schemas/AssetCode"}, {"type": "null"}]},
          "network": {"oneOf": [{"$ref": "#/components/schemas/NetworkCode"}, {"type": "null"}]},
          "status": {"type": "string", "enum": ["new", "waiting", "partial", "paid", "expired", "aml_rejected"]},
          "return_url": {"type": ["string", "null"]},
          "success_url": {"type": ["string", "null"]},
          "cancel_url": {"type": ["string", "null"]},
          "transaction_list": {"type": "array", "items": {"type": "string"}},
          "allowed_coins": {"type": "array", "items": {"type": "object", "additionalProperties": true}, "x-runtime-owned": true},
          "allowed_networks": {"type": "object", "additionalProperties": {"type": "array", "items": {"type": "object", "additionalProperties": true}}, "x-runtime-owned": true},
          "provider_card": {"$ref": "#/components/schemas/ProviderCardCapability"},
          "created_at": {"type": "string", "format": "date-time"},
          "expired_at": {"type": ["string", "null"], "format": "date-time"},
          "finished_at": {"type": ["string", "null"]}
        }
      },
      "ProviderCardOrderCreateRequest": {
        "type": "object",
        "properties": {
          "email": {
            "type": ["string", "null"],
            "format": "email"
          }
        },
        "description": "Only email is accepted as public input. Provider, coin, and network are API-owned."
      },
      "ProviderCardOrder": {
        "type": "object",
        "required": ["id", "provider", "local_status", "expires_at"],
        "properties": {
          "id": {"type": "string"},
          "provider": {"type": "string"},
          "local_status": {
            "type": "string",
            "enum": ["created", "redirect_pending", "provider_pending", "payout_tx_pending", "payout_seen", "paid", "failed", "expired", "blocked_missing_payout_tx_hash", "payout_timeout", "wrong_destination", "wrong_network", "wrong_asset", "amount_mismatch", "duplicate_payout", "late_payout", "reconciliation_exception"]
          },
          "expires_at": {"type": "string", "format": "date-time"},
          "redirect_url": {"type": "string", "format": "uri", "description": "Present only while the redirect is active."},
          "failure_code": {"type": "string", "description": "Present for failed or blocked terminal states."}
        }
      },
      "ProviderCardCapability": {
        "type": "object",
        "required": ["enabled", "providers", "active_order", "disabled_reason", "minimum_amount_cents", "remaining_amount_cents"],
        "properties": {
          "enabled": {"type": "boolean"},
          "providers": {"type": "array", "items": {"type": "object", "required": ["provider", "enabled"], "properties": {"provider": {"type": "string"}, "enabled": {"type": "boolean"}}}},
          "active_order": {"oneOf": [{"$ref": "#/components/schemas/ProviderCardOrder"}, {"type": "null"}]},
          "disabled_reason": {"type": ["string", "null"]},
          "minimum_amount_cents": {"type": "integer"},
          "remaining_amount_cents": {"type": "integer"}
        },
        "x-runtime-owned": true
      },
      "ProviderCardOrderCreateResponse": {
        "type": "object",
        "required": ["data", "status"],
        "properties": {
          "data": {
            "type": "object",
            "required": ["provider_card_order", "reused"],
            "properties": {
              "provider_card_order": {"$ref": "#/components/schemas/ProviderCardOrder"},
              "reused": {"type": "boolean"}
            }
          },
          "status": {"const": "success"}
        }
      },
      "ProviderCardError": {
        "allOf": [
          {"$ref": "#/components/schemas/ControllerError"},
          {
            "type": "object",
            "required": ["failure_code"],
            "properties": {
              "failure_code": {"type": "string"}
            }
          }
        ]
      },
      "WithdrawalRequest": {
        "type": "object",
        "required": ["network", "coin", "amount", "to_address"],
        "properties": {
          "network": {"$ref": "#/components/schemas/NetworkCode"},
          "coin": {"$ref": "#/components/schemas/AssetCode"},
          "amount": {"$ref": "#/components/schemas/NonNegativeDecimalString", "description": "Human-readable coin amount. Runtime min/max depend on the selected pair."},
          "to_address": {"type": "string", "minLength": 10, "maxLength": 128}
        }
      },
      "WithdrawalResponse": {
        "type": "object",
        "required": ["data", "status"],
        "properties": {
          "data": {
            "type": "object",
            "required": ["success", "withdrawal_id", "message", "status", "amounts", "fees", "fee_payer"],
            "properties": {
              "success": {"const": true},
              "withdrawal_id": {"type": "string"},
              "message": {"type": "string"},
              "status": {"type": "string", "enum": ["pending", "processing", "completed", "failed"]},
              "amounts": {"$ref": "#/components/schemas/RequestedNetAmounts"},
              "fees": {"$ref": "#/components/schemas/FeeBreakdown"},
              "fee_payer": {"$ref": "#/components/schemas/WithdrawalFeePayer"}
            }
          },
          "status": {"const": "success"}
        }
      },
      "RequestedNetAmounts": {
        "type": "object",
        "required": ["requested", "net"],
        "properties": {
          "requested": {"$ref": "#/components/schemas/CryptoUsdPair"},
          "net": {"$ref": "#/components/schemas/CryptoUsdPair"}
        }
      },
      "CryptoUsdPair": {
        "type": "object",
        "required": ["crypto", "usd"],
        "properties": {
          "crypto": {"type": ["string", "null"]},
          "usd": {"type": ["string", "null"]}
        }
      },
      "FeeBreakdown": {
        "type": "object",
        "required": ["merchant", "network", "total"],
        "properties": {
          "merchant": {"$ref": "#/components/schemas/CryptoUsdPair"},
          "network": {"$ref": "#/components/schemas/CryptoUsdPair"},
          "total": {"$ref": "#/components/schemas/CryptoUsdPair"}
        }
      },
      "WithdrawalFeePayer": {
        "type": "object",
        "required": ["merchant_fee", "network_fee"],
        "properties": {
          "merchant_fee": {"type": "boolean", "description": "true means the merchant pays the withdrawal service fee."},
          "network_fee": {"type": "boolean", "description": "true means the merchant pays the withdrawal network fee."}
        }
      },
      "WalletAddressCreateRequest": {
        "type": "object",
        "required": ["network", "coin"],
        "properties": {
          "network": {"$ref": "#/components/schemas/NetworkCode"},
          "coin": {"$ref": "#/components/schemas/AssetCode"},
          "type": {"type": "string", "enum": ["static", "merchant"], "default": "static"},
          "label": {"type": ["string", "null"], "maxLength": 255},
          "webhook_url": {"type": ["string", "null"], "format": "uri", "maxLength": 255}
        }
      },
      "WalletAddressCreateResponse": {
        "type": "object",
        "required": ["data", "status"],
        "properties": {
          "data": {
            "type": "object",
            "required": ["address", "qr_code_url"],
            "properties": {
              "address": {"type": "string"},
              "qr_code_url": {"type": "string", "format": "uri"}
            }
          },
          "status": {"const": "success"}
        }
      },
      "MerchantBalancesResponse": {
        "type": "object",
        "required": ["data", "status"],
        "properties": {
          "data": {
            "type": "object",
            "required": ["total_balance_usd", "total_frozen_balance_usd", "total_available_balance_usd", "balances"],
            "properties": {
              "total_balance_usd": {"$ref": "#/components/schemas/NonNegativeDecimalString"},
              "total_frozen_balance_usd": {"$ref": "#/components/schemas/NonNegativeDecimalString"},
              "total_available_balance_usd": {"$ref": "#/components/schemas/NonNegativeDecimalString"},
              "balances": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/MerchantBalance"
                }
              }
            }
          },
          "status": {"const": "success"}
        },
        "x-runtime-owned": true
      },
      "MerchantBalance": {
        "type": "object",
        "required": ["network", "coin", "balance", "available_balance", "frozen_balance", "coin_exchange_frozen_balance", "usd_rate", "usd_value", "frozen_usd_value", "available_usd_value", "coin_exchange_frozen_usd_value"],
        "properties": {
          "network": {"$ref": "#/components/schemas/NetworkCode"},
          "coin": {"$ref": "#/components/schemas/AssetCode"},
          "balance": {"$ref": "#/components/schemas/NonNegativeDecimalString"},
          "available_balance": {"$ref": "#/components/schemas/NonNegativeDecimalString"},
          "frozen_balance": {"$ref": "#/components/schemas/NonNegativeDecimalString"},
          "coin_exchange_frozen_balance": {"$ref": "#/components/schemas/NonNegativeDecimalString"},
          "usd_rate": {"$ref": "#/components/schemas/NonNegativeDecimalString"},
          "usd_value": {"$ref": "#/components/schemas/NonNegativeDecimalString"},
          "frozen_usd_value": {"$ref": "#/components/schemas/NonNegativeDecimalString"},
          "available_usd_value": {"$ref": "#/components/schemas/NonNegativeDecimalString"},
          "coin_exchange_frozen_usd_value": {"$ref": "#/components/schemas/NonNegativeDecimalString"}
        }
      },
      "MerchantFeesResponse": {
        "type": "object",
        "required": ["data", "status"],
        "properties": {
          "data": {
            "type": "object",
            "required": ["service_fee_percent", "static_wallet_fee_percent", "withdrawal_fee_percent", "pay_withdrawal_service_fee", "pay_withdrawal_network_fee", "is_auto_exchange", "network_fees"],
            "properties": {
              "service_fee_percent": {"type": "string"},
              "static_wallet_fee_percent": {"type": "string"},
              "withdrawal_fee_percent": {"type": "string"},
              "pay_withdrawal_service_fee": {"type": "boolean"},
              "pay_withdrawal_network_fee": {"type": "boolean"},
              "is_auto_exchange": {"type": "boolean"},
              "auto_exchange_coin": {"type": ["string", "null"]},
              "auto_exchange_network": {"type": ["string", "null"]},
              "auto_exchange_min_usd_amount": {"type": ["string", "number", "integer", "null"]},
              "invoice_underpayment_percent": {"type": ["string", "number", "integer", "null"]},
              "invoice_underpayment_max_amount": {"type": ["string", "number", "integer", "null"]},
              "invoice_underpayment_max_currency": {"type": ["string", "null"]},
              "network_fees": {
                "type": "array",
                "items": {
                  "type": "object",
                  "required": ["network", "coin", "network_fee"],
                  "properties": {
                    "network": {"$ref": "#/components/schemas/NetworkCode"},
                    "coin": {"$ref": "#/components/schemas/AssetCode"},
                    "network_fee": {"type": "string"}
                  }
                }
              }
            }
          },
          "status": {"const": "success"}
        },
        "x-runtime-owned": true
      },
      "CoinRateResponse": {
        "type": "object",
        "required": ["data", "status"],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CoinRateEntry"
            }
          },
          "status": {"const": "success"}
        },
        "x-runtime-owned": true
      },
      "CoinRateEntry": {
        "type": "object",
        "required": ["coin", "quotes", "networks"],
        "properties": {
          "coin": {
            "type": "object",
            "required": ["symbol", "name", "type"],
            "properties": {
              "symbol": {"type": "string"},
              "name": {"type": "string"},
              "type": {"type": "string", "enum": ["crypto", "fiat"]}
            }
          },
          "quotes": {
            "type": "array",
            "items": {
              "type": "object",
              "required": ["currency_to", "price", "type"],
              "properties": {
                "currency_to": {"type": "string"},
                "price": {"type": "string"},
                "type": {"type": "string", "enum": ["crypto", "fiat"]}
              }
            }
          },
          "networks": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CoinRateNetwork"
            }
          }
        }
      },
      "CoinRateNetwork": {
        "type": "object",
        "required": ["network", "name", "type", "deposit_enabled", "withdraw_enabled", "min_deposit", "min_withdrawal", "max_withdrawal", "network_fee", "decimals"],
        "properties": {
          "network": {"$ref": "#/components/schemas/NetworkCode"},
          "name": {"type": "string"},
          "type": {"type": "string", "enum": ["crypto", "fiat"]},
          "deposit_enabled": {"type": "boolean"},
          "withdraw_enabled": {"type": "boolean"},
          "min_deposit": {"type": ["string", "null"]},
          "min_withdrawal": {"type": ["string", "null"]},
          "max_withdrawal": {"type": ["string", "null"]},
          "network_fee": {"type": ["string", "null"]},
          "decimals": {"type": ["integer", "null"]}
        }
      },
      "CoinCatalogResponse": {
        "type": "object",
        "required": ["data", "status"],
        "properties": {
          "data": {
            "type": "object",
            "required": ["coins"],
            "properties": {
              "coins": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/CoinCatalogEntry"
                }
              }
            }
          },
          "status": {"const": "success"}
        },
        "x-runtime-owned": true
      },
      "CoinCatalogEntry": {
        "type": "object",
        "required": ["coin", "networks"],
        "properties": {
          "coin": {
            "type": "object",
            "required": ["symbol", "label"],
            "properties": {
              "symbol": {"type": "string"},
              "label": {"type": "string"}
            }
          },
          "networks": {
            "type": "array",
            "items": {
              "type": "object",
              "required": ["network", "title", "network_fee", "service_fee", "min_withdrawal"],
              "properties": {
                "network": {"type": "string"},
                "title": {"type": "string"},
                "network_fee": {"type": ["string", "null"]},
                "service_fee": {"type": "string"},
                "min_withdrawal": {"type": ["string", "null"]}
              }
            }
          }
        }
      },
      "WebhookMoney": {
        "type": "object",
        "required": ["amount", "currency", "crypto"],
        "properties": {
          "amount": {"type": ["string", "null"]},
          "currency": {"const": "usd"},
          "crypto": {"type": ["string", "null"]}
        }
      },
      "WebhookFees": {
        "type": "object",
        "required": ["merchant", "network", "total"],
        "properties": {
          "merchant": {"$ref": "#/components/schemas/WebhookMoney"},
          "network": {"$ref": "#/components/schemas/WebhookMoney"},
          "total": {"$ref": "#/components/schemas/WebhookMoney"}
        }
      },
      "InvoiceWebhook": {
        "type": "object",
        "required": ["event", "timestamp", "data"],
        "properties": {
          "event": {"type": "string", "enum": ["invoice.paid", "invoice.expired"]},
          "timestamp": {"type": "integer"},
          "data": {
            "type": "object",
            "required": ["invoice_id", "order_id", "code", "status", "amounts", "fees", "created_at", "fee_payer"],
            "properties": {
              "invoice_id": {"type": "string"},
              "order_id": {"type": "string"},
              "code": {"type": "string"},
              "status": {"type": "string"},
              "amounts": {
                "type": "object",
                "required": ["requested", "paid"],
                "properties": {
                  "requested": {"$ref": "#/components/schemas/WebhookMoney"},
                  "paid": {"$ref": "#/components/schemas/WebhookMoney"}
                }
              },
              "fees": {"$ref": "#/components/schemas/WebhookFees"},
              "payment": {"type": "object", "additionalProperties": true},
              "created_at": {"type": "string", "format": "date-time"},
              "paid_at": {"type": "string", "format": "date-time"},
              "expired_at": {"type": "string", "format": "date-time"},
              "fee_payer": {
                "type": "object",
                "required": ["merchant_fee", "network_fee"],
                "properties": {
                  "merchant_fee": {"type": "boolean", "description": "For invoice events, true means the customer pays the merchant service fee."},
                  "network_fee": {"type": "boolean", "description": "For invoice events, true means the customer pays the network fee."}
                }
              }
            }
          }
        }
      },
      "WalletTransactionWebhook": {
        "type": "object",
        "required": ["event", "timestamp", "data"],
        "properties": {
          "event": {"const": "wallet.transaction"},
          "timestamp": {"type": "integer"},
          "data": {
            "type": "object",
            "required": ["wallet", "transaction"],
            "properties": {
              "wallet": {
                "type": "object",
                "required": ["address", "network", "coin", "label", "rate"],
                "properties": {
                  "address": {"type": "string"},
                  "network": {"$ref": "#/components/schemas/NetworkCode"},
                  "coin": {"$ref": "#/components/schemas/AssetCode"},
                  "label": {"type": ["string", "null"]},
                  "rate": {"type": "string"}
                }
              },
              "transaction": {
                "type": "object",
                "required": ["id", "hash", "block_number", "amounts", "fees", "from_address", "to_address", "status", "timestamp"],
                "properties": {
                  "id": {"type": "string"},
                  "hash": {"type": "string"},
                  "block_number": {"type": ["string", "integer", "null"]},
                  "amounts": {
                    "type": "object",
                    "required": ["gross", "net"],
                    "properties": {
                      "gross": {"$ref": "#/components/schemas/WebhookMoney"},
                      "net": {"$ref": "#/components/schemas/WebhookMoney"}
                    }
                  },
                  "fees": {"$ref": "#/components/schemas/WebhookFees"},
                  "from_address": {"type": ["string", "null"]},
                  "to_address": {"type": ["string", "null"]},
                  "status": {"type": "string"},
                  "timestamp": {"type": ["string", "integer", "null"]}
                }
              }
            }
          }
        }
      },
      "WithdrawalWebhook": {
        "type": "object",
        "required": ["event", "timestamp", "data"],
        "properties": {
          "event": {"type": "string", "enum": ["withdrawal.in_progress", "withdrawal.success", "withdrawal.failed"]},
          "timestamp": {"type": "integer"},
          "data": {
            "type": "object",
            "required": ["withdrawal_id", "status", "amounts", "fees", "payment", "created_at", "fee_payer"],
            "properties": {
              "withdrawal_id": {"type": "string"},
              "status": {"type": "string"},
              "amounts": {
                "type": "object",
                "required": ["requested", "net"],
                "properties": {
                  "requested": {"$ref": "#/components/schemas/WebhookMoney"},
                  "net": {"$ref": "#/components/schemas/WebhookMoney"}
                }
              },
              "fees": {"$ref": "#/components/schemas/WebhookFees"},
              "payment": {"type": "object", "additionalProperties": true},
              "created_at": {"type": "string", "format": "date-time"},
              "updated_at": {"type": "string", "format": "date-time"},
              "transaction_hash": {"type": "string"},
              "error_message": {"type": "string"},
              "fee_payer": {
                "type": "object",
                "required": ["merchant_fee", "network_fee"],
                "properties": {
                  "merchant_fee": {"type": "boolean", "description": "For withdrawal events, true means the merchant pays the service fee."},
                  "network_fee": {"type": "boolean", "description": "For withdrawal events, true means the merchant pays the network fee."}
                }
              }
            }
          }
        }
      },
      "AmlRejectedWebhook": {
        "type": "object",
        "required": ["event", "timestamp", "data"],
        "properties": {
          "event": {"type": "string", "enum": ["aml.rejected.invoice", "aml.rejected.static_wallet"]},
          "timestamp": {"type": "integer"},
          "data": {
            "type": "object",
            "required": ["wallet_address", "risk_score", "risk_level", "risk_details"],
            "properties": {
              "wallet_address": {"type": "string"},
              "risk_score": {"type": ["integer", "null"]},
              "risk_level": {"type": ["string", "null"]},
              "risk_details": {"type": "object", "additionalProperties": true},
              "amounts": {"$ref": "#/components/schemas/WebhookMoney"},
              "coin": {"type": ["string", "null"]},
              "network": {"type": ["string", "null"]},
              "invoice": {"type": "object", "additionalProperties": true},
              "static_wallet": {"type": "object", "additionalProperties": true}
            }
          }
        }
      },
      "TestWebhook": {
        "type": "object",
        "required": ["event", "timestamp", "data"],
        "properties": {
          "event": {"const": "test"},
          "timestamp": {"type": "integer"},
          "data": {"type": "object", "additionalProperties": true}
        }
      }
    }
  }
}
