{
  "openapi": "3.0.3",
  "info": {
    "title": "Infini Merchant Customer Deposit API",
    "version": "0.1.0",
    "description": "All operations use /v2/merchant-customer and Ed25519 v2 authentication. See [Integration guide](/docs/en/customer-deposits-api) and [Authentication](/docs/en/4-authorization). Online Try it is disabled; sign on the merchant backend. Fees are merchant-paid. Freeze price, fee policy and settlement currency at network confirmation; below-minimum fees are additional."
  },
  "servers": [
    {
      "url": "https://openapi.infini.money/v2/merchant-customer",
      "description": "Production"
    },
    {
      "url": "https://openapi-sandbox.infini.money/v2/merchant-customer",
      "description": "Sandbox"
    }
  ],
  "tags": [
    {
      "name": "Currencies",
      "description": "Available deposit assets and networks."
    },
    {
      "name": "Customers",
      "description": "Customer profiles and quota."
    },
    {
      "name": "Addresses",
      "description": "Create and query permanent address bindings."
    },
    {
      "name": "Deposit webhooks",
      "description": "Deposit status events sent by Infini to the merchant Webhook URL."
    }
  ],
  "paths": {
    "/currencies": {
      "get": {
        "operationId": "listMerchantCustomerDepositCurrencies",
        "summary": "List supported deposit currencies",
        "description": "Requires merchant_customer.read. Returns available asset/network pairs and current display thresholds. Filters with no match return data=[].",
        "tags": [
          "Currencies"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/KeyIDHeader"
          },
          {
            "$ref": "#/components/parameters/TimestampHeader"
          },
          {
            "$ref": "#/components/parameters/NonceHeader"
          },
          {
            "$ref": "#/components/parameters/DigestHeader"
          },
          {
            "$ref": "#/components/parameters/AuthorizationHeader"
          },
          {
            "name": "asset",
            "in": "query",
            "required": false,
            "description": "Optional asset filter.",
            "schema": {
              "type": "string",
              "maxLength": 12,
              "example": "USDT"
            }
          },
          {
            "name": "network",
            "in": "query",
            "required": false,
            "description": "Optional network filter.",
            "schema": {
              "type": "string",
              "maxLength": 32,
              "example": "ETHEREUM"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Supported currencies and current thresholds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CurrenciesEnvelope"
                },
                "example": {
                  "code": 0,
                  "message": "",
                  "data": [
                    {
                      "asset": "USDT",
                      "asset_name": "Tether",
                      "networks": [
                        {
                          "network": "ETHEREUM",
                          "network_name": "Ethereum",
                          "min_deposit_amount": "0.01",
                          "fixed_fee": "0.01"
                        }
                      ]
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/customers": {
      "post": {
        "operationId": "upsertMerchantCustomer",
        "summary": "Create or update a customer",
        "description": "Requires merchant_customer.write. Unique by external_user_id. Create returns 201; existing returns 200. Explicitly supplied profile fields are updated; omitted fields are preserved; null or empty clears a field. IDs never change. Identical retries do not change updated_at. Existing updates consume no additional quota and work at the quota limit. Creating a Customer does not allocate a wallet.",
        "tags": [
          "Customers"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/KeyIDHeader"
          },
          {
            "$ref": "#/components/parameters/TimestampHeader"
          },
          {
            "$ref": "#/components/parameters/NonceHeader"
          },
          {
            "$ref": "#/components/parameters/DigestHeader"
          },
          {
            "$ref": "#/components/parameters/AuthorizationHeader"
          }
        ],
        "responses": {
          "200": {
            "description": "Existing customer returned or profile updated.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerEnvelope"
                },
                "example": {
                  "code": 0,
                  "message": "",
                  "data": {
                    "customer_id": 583174926,
                    "external_user_id": "user_1001",
                    "name": "Alice",
                    "email": "alice@example.com",
                    "remark": "VIP customer",
                    "created_at": 1794211200,
                    "updated_at": 1794211200
                  }
                }
              }
            }
          },
          "201": {
            "description": "Customer created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerEnvelope"
                },
                "example": {
                  "code": 0,
                  "message": "",
                  "data": {
                    "customer_id": 583174926,
                    "external_user_id": "user_1001",
                    "name": "Alice",
                    "email": "alice@example.com",
                    "remark": "VIP customer",
                    "created_at": 1794211200,
                    "updated_at": 1794211200
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpsertCustomerRequest"
              },
              "example": {
                "external_user_id": "user_1001",
                "name": "Alice",
                "email": "alice@example.com",
                "remark": "VIP customer"
              }
            }
          }
        }
      },
      "get": {
        "operationId": "getMerchantCustomer",
        "summary": "Get a customer",
        "description": "Requires merchant_customer.read. Supply exactly one of customer_id or external_user_id. Read only; does not create or update.",
        "tags": [
          "Customers"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/KeyIDHeader"
          },
          {
            "$ref": "#/components/parameters/TimestampHeader"
          },
          {
            "$ref": "#/components/parameters/NonceHeader"
          },
          {
            "$ref": "#/components/parameters/DigestHeader"
          },
          {
            "$ref": "#/components/parameters/AuthorizationHeader"
          },
          {
            "name": "customer_id",
            "in": "query",
            "required": false,
            "description": "Use instead of external_user_id.",
            "schema": {
              "$ref": "#/components/schemas/CustomerID"
            }
          },
          {
            "name": "external_user_id",
            "in": "query",
            "required": false,
            "description": "Use instead of customer_id.",
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 80,
              "example": "user_1001"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Customer found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerEnvelope"
                },
                "example": {
                  "code": 0,
                  "message": "",
                  "data": {
                    "customer_id": 583174926,
                    "external_user_id": "user_1001",
                    "name": "Alice",
                    "email": "alice@example.com",
                    "remark": "VIP customer",
                    "created_at": 1794211200,
                    "updated_at": 1794211200
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/customers/quota": {
      "get": {
        "operationId": "getMerchantCustomerQuota",
        "summary": "Get customer quota",
        "description": "Requires merchant_customer.read. Returns only limit and used. Calculate remaining as max(limit-used,0). Quota is per Customer, not per address, and is not reserved by this query. Merchant overrides may differ from environment defaults.",
        "tags": [
          "Customers"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/KeyIDHeader"
          },
          {
            "$ref": "#/components/parameters/TimestampHeader"
          },
          {
            "$ref": "#/components/parameters/NonceHeader"
          },
          {
            "$ref": "#/components/parameters/DigestHeader"
          },
          {
            "$ref": "#/components/parameters/AuthorizationHeader"
          }
        ],
        "responses": {
          "200": {
            "description": "Effective Customer quota.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/QuotaEnvelope"
                },
                "example": {
                  "code": 0,
                  "message": "",
                  "data": {
                    "limit": 50,
                    "used": 12
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/addresses": {
      "post": {
        "operationId": "createMerchantCustomerDepositAddress",
        "summary": "Create or reuse a deposit address",
        "description": "Requires merchant_customer.write. Business key: merchant + environment + customer_id + asset + network. Returns 201 for a new ready binding, 200 for reuse. EVM networks share a physical address for the same Customer; binding IDs remain distinct. Same-network assets such as TRON TRX/USDT also share an address. Supported unrequested asset/network deposits to the owned address are automatically identified and settled. Concurrent or unknown allocation results return address_processing; query or retry with the same business fields. Never treat a timeout as proof of failure.",
        "tags": [
          "Addresses"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/KeyIDHeader"
          },
          {
            "$ref": "#/components/parameters/TimestampHeader"
          },
          {
            "$ref": "#/components/parameters/NonceHeader"
          },
          {
            "$ref": "#/components/parameters/DigestHeader"
          },
          {
            "$ref": "#/components/parameters/AuthorizationHeader"
          }
        ],
        "responses": {
          "200": {
            "description": "Existing ready binding reused.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AddressEnvelope"
                },
                "example": {
                  "code": 0,
                  "message": "",
                  "data": {
                    "deposit_address_id": "d498f76d-42a9-447c-bdad-c10f72d18844",
                    "customer_id": 583174926,
                    "asset": "USDT",
                    "network": "ETHEREUM",
                    "address": "0x1111111111111111111111111111111111111111",
                    "required_confirmations": 12,
                    "min_deposit_amount": "0.01",
                    "created_at": 1794211260
                  }
                }
              }
            }
          },
          "201": {
            "description": "Ready address binding created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AddressEnvelope"
                },
                "example": {
                  "code": 0,
                  "message": "",
                  "data": {
                    "deposit_address_id": "d498f76d-42a9-447c-bdad-c10f72d18844",
                    "customer_id": 583174926,
                    "asset": "USDT",
                    "network": "ETHEREUM",
                    "address": "0x1111111111111111111111111111111111111111",
                    "required_confirmations": 12,
                    "min_deposit_amount": "0.01",
                    "created_at": 1794211260
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AddressRequest"
              },
              "example": {
                "customer_id": 583174926,
                "asset": "USDT",
                "network": "ETHEREUM"
              }
            }
          }
        }
      },
      "get": {
        "operationId": "getMerchantCustomerDepositAddress",
        "summary": "Get a deposit address",
        "description": "Requires merchant_customer.read. Read-only lookup by customer_id, asset and network. Does not allocate a wallet or create a binding. Unknown binding returns 404; an allocation still being prepared returns address_processing.",
        "tags": [
          "Addresses"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/KeyIDHeader"
          },
          {
            "$ref": "#/components/parameters/TimestampHeader"
          },
          {
            "$ref": "#/components/parameters/NonceHeader"
          },
          {
            "$ref": "#/components/parameters/DigestHeader"
          },
          {
            "$ref": "#/components/parameters/AuthorizationHeader"
          },
          {
            "name": "customer_id",
            "in": "query",
            "required": true,
            "description": "Customer ID.",
            "schema": {
              "$ref": "#/components/schemas/CustomerID"
            }
          },
          {
            "name": "asset",
            "in": "query",
            "required": true,
            "description": "Asset code.",
            "schema": {
              "type": "string",
              "maxLength": 12,
              "example": "USDT"
            }
          },
          {
            "name": "network",
            "in": "query",
            "required": true,
            "description": "Network code.",
            "schema": {
              "type": "string",
              "maxLength": 32,
              "example": "ETHEREUM"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Existing ready address binding.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AddressEnvelope"
                },
                "example": {
                  "code": 0,
                  "message": "",
                  "data": {
                    "deposit_address_id": "d498f76d-42a9-447c-bdad-c10f72d18844",
                    "customer_id": 583174926,
                    "asset": "USDT",
                    "network": "ETHEREUM",
                    "address": "0x1111111111111111111111111111111111111111",
                    "required_confirmations": 12,
                    "min_deposit_amount": "0.01",
                    "created_at": 1794211260
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    }
  },
  "components": {
    "parameters": {
      "KeyIDHeader": {
        "name": "X-API-Key-ID",
        "in": "header",
        "required": true,
        "description": "32-character Base58 credential ID.",
        "schema": {
          "type": "string",
          "example": "<KEY_ID>"
        }
      },
      "TimestampHeader": {
        "name": "X-API-Timestamp",
        "in": "header",
        "required": true,
        "description": "Current Unix seconds; tolerance ±300 seconds.",
        "schema": {
          "type": "string",
          "example": "1794211200"
        }
      },
      "NonceHeader": {
        "name": "X-API-Nonce",
        "in": "header",
        "required": true,
        "description": "16 cryptographically random bytes as unpadded Base64URL; fresh on every attempt.",
        "schema": {
          "type": "string",
          "example": "AAECAwQFBgcICQoLDA0ODw"
        }
      },
      "DigestHeader": {
        "name": "Digest",
        "in": "header",
        "required": true,
        "description": "SHA-256= plus padded standard Base64 of exact body bytes; required also on GET with an empty body.",
        "schema": {
          "type": "string",
          "example": "SHA-256=47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU="
        }
      },
      "AuthorizationHeader": {
        "name": "Authorization",
        "in": "header",
        "required": true,
        "description": "Ed25519 signature=\"BASE64_SIGNATURE\". Sign locally; never upload your private key. See the Authentication guide.",
        "schema": {
          "type": "string",
          "example": "Ed25519 signature=\"<BASE64_SIGNATURE>\""
        }
      }
    },
    "responses": {
      "BadRequest": {
        "description": "Invalid request parameters or asset/network combination.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            },
            "examples": {
              "invalid_parameter": {
                "summary": "Invalid request field",
                "value": {
                  "code": 30013,
                  "message": "Invalid parameter",
                  "data": {
                    "error": "invalid_parameter",
                    "field": "external_user_id",
                    "retryable": false
                  }
                }
              },
              "unsupported_chain_token": {
                "summary": "Unsupported asset and network",
                "value": {
                  "code": 40007,
                  "message": "Unsupported chain or token",
                  "data": {
                    "error": "unsupported_chain_token",
                    "field": "network",
                    "retryable": false
                  }
                }
              }
            }
          }
        }
      },
      "Unauthorized": {
        "description": "Ed25519 credential, signature, digest, timestamp or nonce validation failed.",
        "content": {
          "application/json": {
            "schema": {
              "oneOf": [
                {
                  "$ref": "#/components/schemas/ErrorEnvelope"
                },
                {
                  "$ref": "#/components/schemas/GatewayError"
                }
              ]
            },
            "example": {
              "message": "client request can't be validated"
            }
          }
        }
      },
      "Forbidden": {
        "description": "API key permission or access policy denied.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            },
            "examples": {
              "permission_denied": {
                "summary": "Permission denied",
                "value": {
                  "code": 403,
                  "message": "Permission denied",
                  "data": {
                    "error": "permission_denied",
                    "field": null,
                    "retryable": false
                  }
                }
              }
            }
          }
        }
      },
      "NotFound": {
        "description": "Resource not found in the authenticated merchant and environment.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            },
            "examples": {
              "customer_not_found": {
                "summary": "Customer not found",
                "value": {
                  "code": 47001,
                  "message": "Customer not found",
                  "data": {
                    "error": "customer_not_found",
                    "field": "customer_id",
                    "retryable": false
                  }
                }
              },
              "deposit_address_not_found": {
                "summary": "Address binding not found",
                "value": {
                  "code": 47002,
                  "message": "Deposit address not found",
                  "data": {
                    "error": "deposit_address_not_found",
                    "field": null,
                    "retryable": false
                  }
                }
              }
            }
          }
        }
      },
      "Conflict": {
        "description": "Quota, address processing or currency availability conflict.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            },
            "examples": {
              "customer_limit_exceeded": {
                "summary": "Customer quota reached",
                "value": {
                  "code": 47003,
                  "message": "Customer limit reached",
                  "data": {
                    "error": "customer_limit_exceeded",
                    "field": "external_user_id",
                    "retryable": false
                  }
                }
              },
              "address_processing": {
                "summary": "Address allocation in progress",
                "value": {
                  "code": 47004,
                  "message": "Address allocation is processing",
                  "data": {
                    "error": "address_processing",
                    "field": null,
                    "retryable": true
                  }
                }
              },
              "currency_disabled": {
                "summary": "Currency disabled",
                "value": {
                  "code": 40915,
                  "message": "Currency is disabled",
                  "data": {
                    "error": "currency_disabled",
                    "field": "asset",
                    "retryable": false
                  }
                }
              }
            }
          }
        }
      },
      "ServiceUnavailable": {
        "description": "Retry with the same business fields after backoff.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            },
            "examples": {
              "price_unavailable": {
                "summary": "Price temporarily unavailable",
                "value": {
                  "code": 47005,
                  "message": "Price is temporarily unavailable",
                  "data": {
                    "error": "price_unavailable",
                    "field": null,
                    "retryable": true
                  }
                }
              },
              "dependency_unavailable": {
                "summary": "Dependency temporarily unavailable",
                "value": {
                  "code": 47006,
                  "message": "Dependency is temporarily unavailable",
                  "data": {
                    "error": "dependency_unavailable",
                    "field": null,
                    "retryable": true
                  }
                }
              }
            }
          }
        }
      },
      "InternalError": {
        "description": "Unexpected internal error.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorEnvelope"
            },
            "examples": {
              "internal_error": {
                "summary": "Internal error",
                "value": {
                  "code": 500,
                  "message": "Internal error",
                  "data": {
                    "error": "internal_error",
                    "field": null,
                    "retryable": true
                  }
                }
              }
            }
          }
        }
      }
    },
    "schemas": {
      "CustomerID": {
        "type": "integer",
        "description": "Positive signed 32-bit Customer ID.",
        "example": 583174926,
        "format": "int32",
        "minimum": 1,
        "maximum": 2147483647
      },
      "Customer": {
        "type": "object",
        "required": [
          "customer_id",
          "external_user_id",
          "name",
          "email",
          "remark",
          "created_at",
          "updated_at"
        ],
        "properties": {
          "customer_id": {
            "$ref": "#/components/schemas/CustomerID"
          },
          "external_user_id": {
            "type": "string",
            "description": "Immutable merchant user ID, case-sensitive.",
            "example": "user_1001",
            "minLength": 1,
            "maxLength": 80
          },
          "name": {
            "type": "string",
            "description": "Customer name; null when absent.",
            "example": "Alice",
            "nullable": true,
            "maxLength": 256
          },
          "email": {
            "type": "string",
            "description": "Normalized lowercase email; null when absent.",
            "example": "alice@example.com",
            "nullable": true,
            "maxLength": 256
          },
          "remark": {
            "type": "string",
            "description": "Merchant remark; null when absent.",
            "example": "VIP customer",
            "nullable": true,
            "maxLength": 500
          },
          "created_at": {
            "type": "integer",
            "description": "First creation time. Unix seconds, not milliseconds.",
            "example": 1794211200,
            "format": "int64",
            "minimum": 0
          },
          "updated_at": {
            "type": "integer",
            "description": "Last actual profile change; unchanged retries do not advance it. Unix seconds, not milliseconds.",
            "example": 1794211200,
            "format": "int64",
            "minimum": 0
          }
        }
      },
      "UpsertCustomerRequest": {
        "type": "object",
        "required": [
          "external_user_id"
        ],
        "properties": {
          "external_user_id": {
            "type": "string",
            "description": "Immutable merchant user ID, case-sensitive.",
            "example": "user_1001",
            "minLength": 1,
            "maxLength": 80
          },
          "name": {
            "type": "string",
            "description": "Customer name; null when absent.",
            "example": "Alice",
            "nullable": true,
            "maxLength": 256
          },
          "email": {
            "type": "string",
            "description": "Normalized lowercase email; null when absent.",
            "example": "alice@example.com",
            "nullable": true,
            "maxLength": 256
          },
          "remark": {
            "type": "string",
            "description": "Merchant remark; null when absent.",
            "example": "VIP customer",
            "nullable": true,
            "maxLength": 500
          }
        }
      },
      "CustomerQuota": {
        "type": "object",
        "required": [
          "limit",
          "used"
        ],
        "properties": {
          "limit": {
            "type": "integer",
            "description": "Effective Customer limit for this merchant and environment.",
            "example": 50,
            "minimum": 0
          },
          "used": {
            "type": "integer",
            "description": "Created Customer count; repeated updates do not consume quota. Calculate remaining as max(limit - used, 0).",
            "example": 12,
            "minimum": 0
          }
        }
      },
      "AddressRequest": {
        "type": "object",
        "required": [
          "customer_id",
          "asset",
          "network"
        ],
        "properties": {
          "customer_id": {
            "$ref": "#/components/schemas/CustomerID"
          },
          "asset": {
            "type": "string",
            "description": "Supported asset code; query currencies for availability.",
            "example": "USDT",
            "minLength": 1,
            "maxLength": 12
          },
          "network": {
            "type": "string",
            "description": "Supported network code.",
            "example": "ETHEREUM",
            "minLength": 1,
            "maxLength": 32
          }
        }
      },
      "DepositAddress": {
        "type": "object",
        "required": [
          "deposit_address_id",
          "customer_id",
          "asset",
          "network",
          "address",
          "required_confirmations",
          "min_deposit_amount",
          "created_at"
        ],
        "properties": {
          "deposit_address_id": {
            "type": "string",
            "description": "Stable asset/network binding ID; different bindings may share a physical address.",
            "example": "d498f76d-42a9-447c-bdad-c10f72d18844",
            "format": "uuid"
          },
          "customer_id": {
            "$ref": "#/components/schemas/CustomerID"
          },
          "asset": {
            "type": "string",
            "description": "Supported asset code; query currencies for availability.",
            "example": "USDT",
            "minLength": 1,
            "maxLength": 12
          },
          "network": {
            "type": "string",
            "description": "Supported network code.",
            "example": "ETHEREUM",
            "minLength": 1,
            "maxLength": 32
          },
          "address": {
            "type": "string",
            "description": "Ready-to-use address. Example is illustrative only; do not send funds to it.",
            "example": "0x1111111111111111111111111111111111111111",
            "minLength": 1
          },
          "required_confirmations": {
            "type": "integer",
            "description": "Network confirmation requirement; use the actual returned value.",
            "example": 12,
            "minimum": 0
          },
          "min_deposit_amount": {
            "type": "string",
            "description": "Current threshold in asset units, derived from USD configuration and the current price. Zero means no threshold. Does not lock future pricing.",
            "example": "0.01"
          },
          "created_at": {
            "type": "integer",
            "description": "First successful binding time, unchanged on reuse. Unix seconds, not milliseconds.",
            "example": 1794211260,
            "format": "int64",
            "minimum": 0
          }
        }
      },
      "CurrencyNetwork": {
        "type": "object",
        "required": [
          "network",
          "network_name",
          "min_deposit_amount",
          "fixed_fee"
        ],
        "properties": {
          "network": {
            "type": "string",
            "description": "Network code.",
            "example": "ETHEREUM"
          },
          "network_name": {
            "type": "string",
            "description": "Network display name.",
            "example": "Ethereum"
          },
          "min_deposit_amount": {
            "type": "string",
            "description": "Current threshold in asset units, derived from USD configuration and the current price. Zero means no threshold. Does not lock future pricing.",
            "example": "0.01"
          },
          "fixed_fee": {
            "type": "string",
            "description": "Fixed additional below-minimum fee, always denominated in USD. Normal acquiring fees also apply.",
            "example": "0.01"
          }
        }
      },
      "Currency": {
        "type": "object",
        "required": [
          "asset",
          "asset_name",
          "networks"
        ],
        "properties": {
          "asset": {
            "type": "string",
            "description": "Asset code.",
            "example": "USDT"
          },
          "asset_name": {
            "type": "string",
            "description": "Asset display name.",
            "example": "Tether"
          },
          "networks": {
            "type": "array",
            "minItems": 1,
            "items": {
              "$ref": "#/components/schemas/CurrencyNetwork"
            }
          }
        }
      },
      "CustomerEnvelope": {
        "type": "object",
        "required": [
          "code",
          "message",
          "data"
        ],
        "properties": {
          "code": {
            "type": "integer",
            "description": "Zero indicates success.",
            "example": 0,
            "enum": [
              0
            ]
          },
          "message": {
            "type": "string",
            "description": "Response message.",
            "example": ""
          },
          "data": {
            "$ref": "#/components/schemas/Customer"
          }
        }
      },
      "AddressEnvelope": {
        "type": "object",
        "required": [
          "code",
          "message",
          "data"
        ],
        "properties": {
          "code": {
            "type": "integer",
            "description": "Zero indicates success.",
            "example": 0,
            "enum": [
              0
            ]
          },
          "message": {
            "type": "string",
            "description": "Response message.",
            "example": ""
          },
          "data": {
            "$ref": "#/components/schemas/DepositAddress"
          }
        }
      },
      "QuotaEnvelope": {
        "type": "object",
        "required": [
          "code",
          "message",
          "data"
        ],
        "properties": {
          "code": {
            "type": "integer",
            "description": "Zero indicates success.",
            "example": 0,
            "enum": [
              0
            ]
          },
          "message": {
            "type": "string",
            "description": "Response message.",
            "example": ""
          },
          "data": {
            "$ref": "#/components/schemas/CustomerQuota"
          }
        }
      },
      "CurrenciesEnvelope": {
        "type": "object",
        "required": [
          "code",
          "message",
          "data"
        ],
        "properties": {
          "code": {
            "type": "integer",
            "description": "Zero indicates success.",
            "example": 0,
            "enum": [
              0
            ]
          },
          "message": {
            "type": "string",
            "description": "Response message.",
            "example": ""
          },
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Currency"
            }
          }
        }
      },
      "ErrorDetail": {
        "type": "object",
        "required": [
          "error",
          "field",
          "retryable"
        ],
        "properties": {
          "error": {
            "type": "string",
            "description": "Stable machine-readable error identifier.",
            "example": "customer_limit_exceeded"
          },
          "field": {
            "type": "string",
            "description": "Related field, or null.",
            "example": "external_user_id",
            "nullable": true
          },
          "retryable": {
            "type": "boolean",
            "description": "Whether to retry using the same business fields.",
            "example": false
          }
        }
      },
      "ErrorEnvelope": {
        "type": "object",
        "required": [
          "code",
          "message",
          "data"
        ],
        "properties": {
          "code": {
            "type": "integer",
            "description": "Non-zero business error code.",
            "example": 47003,
            "minimum": 1
          },
          "message": {
            "type": "string",
            "description": "Human-readable description; do not branch on this text.",
            "example": "Customer limit reached"
          },
          "data": {
            "$ref": "#/components/schemas/ErrorDetail"
          }
        }
      },
      "GatewayError": {
        "type": "object",
        "required": [
          "message"
        ],
        "properties": {
          "message": {
            "type": "string",
            "description": "Gateway rejection can occur before the application envelope is produced.",
            "example": "client request can't be validated"
          }
        }
      },
      "DepositWebhookData": {
        "type": "object",
        "required": [
          "deposit_id",
          "transaction_id",
          "customer_id",
          "external_user_id",
          "asset",
          "network",
          "amount",
          "address",
          "tx_hash",
          "status",
          "credited_amount",
          "credited_currency",
          "failure_code",
          "failure_message",
          "created_at",
          "updated_at",
          "completed_at"
        ],
        "properties": {
          "deposit_id": {
            "type": "string",
            "description": "Stable deposit identity; one hash can identify multiple deposits.",
            "example": "c2239a50-ce71-4b11-ae83-f69c70e36da7",
            "format": "uuid"
          },
          "transaction_id": {
            "type": "string",
            "description": "Non-null ledger transaction ID only for completed, including zero credit; deduplicate final credit by this ID.",
            "example": "7a2a406e-5d71-4e8a-9bf4-b95fe2308183",
            "nullable": true
          },
          "customer_id": {
            "$ref": "#/components/schemas/CustomerID"
          },
          "external_user_id": {
            "type": "string",
            "description": "Immutable merchant user ID, case-sensitive.",
            "example": "user_1001",
            "minLength": 1,
            "maxLength": 80
          },
          "asset": {
            "type": "string",
            "description": "Supported asset code; query currencies for availability.",
            "example": "USDT",
            "minLength": 1,
            "maxLength": 12
          },
          "network": {
            "type": "string",
            "description": "Supported network code.",
            "example": "ETHEREUM",
            "minLength": 1,
            "maxLength": 32
          },
          "amount": {
            "type": "string",
            "description": "Actual on-chain amount in asset units.",
            "example": "100"
          },
          "address": {
            "type": "string",
            "description": "Ready-to-use address. Example is illustrative only; do not send funds to it.",
            "example": "0x1111111111111111111111111111111111111111",
            "minLength": 1
          },
          "tx_hash": {
            "type": "string",
            "description": "Transaction hash; never use it as the sole deposit or credit deduplication key.",
            "example": "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
          },
          "status": {
            "type": "string",
            "description": "Deposit state corresponding to this event.",
            "example": "completed",
            "enum": [
              "confirming",
              "confirmed",
              "completed",
              "failed"
            ]
          },
          "credited_amount": {
            "type": "string",
            "description": "Actual credit amount; completed requires a value including zero, other events use null.",
            "example": "99",
            "nullable": true
          },
          "credited_currency": {
            "type": "string",
            "description": "Actual credited currency; completed requires a value, other events use null.",
            "example": "USDT",
            "nullable": true
          },
          "failure_code": {
            "type": "string",
            "description": "Non-null only for failed. CHAIN_EXECUTION_FAILED or CHAIN_TRANSACTION_INVALID. KYT delays are not chain failures.",
            "example": null,
            "nullable": true
          },
          "failure_message": {
            "type": "string",
            "description": "Non-null failure explanation only for failed.",
            "example": null,
            "nullable": true
          },
          "created_at": {
            "type": "integer",
            "description": "Deposit creation time. Unix seconds, not milliseconds.",
            "example": 1794211380,
            "format": "int64",
            "minimum": 0
          },
          "updated_at": {
            "type": "integer",
            "description": "This event snapshot update time. Unix seconds, not milliseconds.",
            "example": 1794211500,
            "format": "int64",
            "minimum": 0
          },
          "completed_at": {
            "type": "integer",
            "description": "Ledger processing completion time; null for other states. Unix seconds, not milliseconds.",
            "example": 1794211500,
            "format": "int64",
            "minimum": 0,
            "nullable": true
          }
        }
      },
      "DepositWebhookEnvelope": {
        "type": "object",
        "required": [
          "id",
          "event",
          "version",
          "occurred_at",
          "data"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Delivery event ID; matches X-Webhook-Event-Id and is stable on retry.",
            "example": "a96e5344-d49b-455d-aef5-2469f901c10e"
          },
          "event": {
            "type": "string",
            "description": "Exact subscribed event name.",
            "example": "merchant_customer_deposit.completed",
            "enum": [
              "merchant_customer_deposit.confirming",
              "merchant_customer_deposit.confirmed",
              "merchant_customer_deposit.completed",
              "merchant_customer_deposit.failed"
            ]
          },
          "version": {
            "type": "integer",
            "description": "Public envelope version.",
            "example": 1,
            "enum": [
              1
            ]
          },
          "occurred_at": {
            "type": "integer",
            "description": "Event creation time. Unix seconds, not milliseconds.",
            "example": 1794211500,
            "format": "int64",
            "minimum": 0
          },
          "data": {
            "$ref": "#/components/schemas/DepositWebhookData"
          }
        }
      }
    },
    "securitySchemes": {
      "Ed25519": {
        "type": "apiKey",
        "in": "header",
        "name": "Authorization",
        "description": "Ed25519 signature=\"BASE64_SIGNATURE\" plus X-API-Key-ID, X-API-Timestamp, X-API-Nonce and Digest. Never enter private keys into this reference."
      }
    }
  },
  "security": [
    {
      "Ed25519": []
    }
  ],
  "x-webhooks": {
    "merchant_customer_deposit.confirming": {
      "post": {
        "operationId": "notifyMerchantCustomerDepositConfirming",
        "summary": "Deposit confirming",
        "description": "Recognized deposit awaiting network confirmation. Verify HMAC-SHA256 of timestamp.event_id.raw_payload with the Webhook Secret; deduplicate by event ID. Only completed authorizes user-ledger credit.",
        "tags": [
          "Deposit webhooks"
        ],
        "security": [],
        "parameters": [
          {
            "name": "X-Webhook-Timestamp",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "example": "1794211500"
            }
          },
          {
            "name": "X-Webhook-Event-Id",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "example": "a96e5344-d49b-455d-aef5-2469f901c10e"
            }
          },
          {
            "name": "X-Webhook-Signature-Version",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "example": "v1"
            }
          },
          {
            "name": "X-Webhook-Signature",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "example": "<HEX_HMAC_SHA256>"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DepositWebhookEnvelope"
              },
              "examples": {
                "event": {
                  "summary": "Deposit confirming",
                  "value": {
                    "id": "a96e5344-d49b-455d-aef5-2469f901c10e",
                    "event": "merchant_customer_deposit.confirming",
                    "version": 1,
                    "occurred_at": 1794211500,
                    "data": {
                      "deposit_id": "c2239a50-ce71-4b11-ae83-f69c70e36da7",
                      "transaction_id": null,
                      "customer_id": 583174926,
                      "external_user_id": "user_1001",
                      "asset": "USDT",
                      "network": "ETHEREUM",
                      "amount": "100",
                      "address": "0x1111111111111111111111111111111111111111",
                      "tx_hash": "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
                      "status": "confirming",
                      "credited_amount": null,
                      "credited_currency": null,
                      "failure_code": null,
                      "failure_message": null,
                      "created_at": 1794211380,
                      "updated_at": 1794211500,
                      "completed_at": null
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Return 200 after durably saving the event; process business logic asynchronously."
          }
        }
      }
    },
    "merchant_customer_deposit.confirmed": {
      "post": {
        "operationId": "notifyMerchantCustomerDepositConfirmed",
        "summary": "Deposit confirmed",
        "description": "Network confirmed; merchant credit is not yet complete. Verify HMAC-SHA256 of timestamp.event_id.raw_payload with the Webhook Secret; deduplicate by event ID. Only completed authorizes user-ledger credit.",
        "tags": [
          "Deposit webhooks"
        ],
        "security": [],
        "parameters": [
          {
            "name": "X-Webhook-Timestamp",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "example": "1794211500"
            }
          },
          {
            "name": "X-Webhook-Event-Id",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "example": "a96e5344-d49b-455d-aef5-2469f901c10e"
            }
          },
          {
            "name": "X-Webhook-Signature-Version",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "example": "v1"
            }
          },
          {
            "name": "X-Webhook-Signature",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "example": "<HEX_HMAC_SHA256>"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DepositWebhookEnvelope"
              },
              "examples": {
                "event": {
                  "summary": "Deposit confirmed",
                  "value": {
                    "id": "a96e5344-d49b-455d-aef5-2469f901c10e",
                    "event": "merchant_customer_deposit.confirmed",
                    "version": 1,
                    "occurred_at": 1794211500,
                    "data": {
                      "deposit_id": "c2239a50-ce71-4b11-ae83-f69c70e36da7",
                      "transaction_id": null,
                      "customer_id": 583174926,
                      "external_user_id": "user_1001",
                      "asset": "USDT",
                      "network": "ETHEREUM",
                      "amount": "100",
                      "address": "0x1111111111111111111111111111111111111111",
                      "tx_hash": "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
                      "status": "confirmed",
                      "credited_amount": null,
                      "credited_currency": null,
                      "failure_code": null,
                      "failure_message": null,
                      "created_at": 1794211380,
                      "updated_at": 1794211500,
                      "completed_at": null
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Return 200 after durably saving the event; process business logic asynchronously."
          }
        }
      }
    },
    "merchant_customer_deposit.completed": {
      "post": {
        "operationId": "notifyMerchantCustomerDepositCompleted",
        "summary": "Deposit completed",
        "description": "Ledger processing completed. credited_amount may be zero. Verify HMAC-SHA256 of timestamp.event_id.raw_payload with the Webhook Secret; deduplicate by event ID. Only completed authorizes user-ledger credit.",
        "tags": [
          "Deposit webhooks"
        ],
        "security": [],
        "parameters": [
          {
            "name": "X-Webhook-Timestamp",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "example": "1794211500"
            }
          },
          {
            "name": "X-Webhook-Event-Id",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "example": "a96e5344-d49b-455d-aef5-2469f901c10e"
            }
          },
          {
            "name": "X-Webhook-Signature-Version",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "example": "v1"
            }
          },
          {
            "name": "X-Webhook-Signature",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "example": "<HEX_HMAC_SHA256>"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DepositWebhookEnvelope"
              },
              "examples": {
                "event": {
                  "summary": "Deposit completed",
                  "value": {
                    "id": "a96e5344-d49b-455d-aef5-2469f901c10e",
                    "event": "merchant_customer_deposit.completed",
                    "version": 1,
                    "occurred_at": 1794211500,
                    "data": {
                      "deposit_id": "c2239a50-ce71-4b11-ae83-f69c70e36da7",
                      "transaction_id": "7a2a406e-5d71-4e8a-9bf4-b95fe2308183",
                      "customer_id": 583174926,
                      "external_user_id": "user_1001",
                      "asset": "USDT",
                      "network": "ETHEREUM",
                      "amount": "100",
                      "address": "0x1111111111111111111111111111111111111111",
                      "tx_hash": "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
                      "status": "completed",
                      "credited_amount": "99",
                      "credited_currency": "USDT",
                      "failure_code": null,
                      "failure_message": null,
                      "created_at": 1794211380,
                      "updated_at": 1794211500,
                      "completed_at": 1794211500
                    }
                  }
                },
                "zeroNet": {
                  "summary": "Zero-net completion",
                  "value": {
                    "id": "a96e5344-d49b-455d-aef5-2469f901c10e",
                    "event": "merchant_customer_deposit.completed",
                    "version": 1,
                    "occurred_at": 1794211500,
                    "data": {
                      "deposit_id": "c2239a50-ce71-4b11-ae83-f69c70e36da7",
                      "transaction_id": "7a2a406e-5d71-4e8a-9bf4-b95fe2308183",
                      "customer_id": 583174926,
                      "external_user_id": "user_1001",
                      "asset": "USDT",
                      "network": "ETHEREUM",
                      "amount": "100",
                      "address": "0x1111111111111111111111111111111111111111",
                      "tx_hash": "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
                      "status": "completed",
                      "credited_amount": "0",
                      "credited_currency": "USDT",
                      "failure_code": null,
                      "failure_message": null,
                      "created_at": 1794211380,
                      "updated_at": 1794211500,
                      "completed_at": 1794211500
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Return 200 after durably saving the event; process business logic asynchronously."
          }
        }
      }
    },
    "merchant_customer_deposit.failed": {
      "post": {
        "operationId": "notifyMerchantCustomerDepositFailed",
        "summary": "Deposit failed",
        "description": "Recognized deposit explicitly failed or became invalid on-chain. Verify HMAC-SHA256 of timestamp.event_id.raw_payload with the Webhook Secret; deduplicate by event ID. Only completed authorizes user-ledger credit.",
        "tags": [
          "Deposit webhooks"
        ],
        "security": [],
        "parameters": [
          {
            "name": "X-Webhook-Timestamp",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "example": "1794211500"
            }
          },
          {
            "name": "X-Webhook-Event-Id",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "example": "a96e5344-d49b-455d-aef5-2469f901c10e"
            }
          },
          {
            "name": "X-Webhook-Signature-Version",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "example": "v1"
            }
          },
          {
            "name": "X-Webhook-Signature",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "example": "<HEX_HMAC_SHA256>"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DepositWebhookEnvelope"
              },
              "examples": {
                "event": {
                  "summary": "Deposit failed",
                  "value": {
                    "id": "a96e5344-d49b-455d-aef5-2469f901c10e",
                    "event": "merchant_customer_deposit.failed",
                    "version": 1,
                    "occurred_at": 1794211500,
                    "data": {
                      "deposit_id": "c2239a50-ce71-4b11-ae83-f69c70e36da7",
                      "transaction_id": null,
                      "customer_id": 583174926,
                      "external_user_id": "user_1001",
                      "asset": "USDT",
                      "network": "ETHEREUM",
                      "amount": "100",
                      "address": "0x1111111111111111111111111111111111111111",
                      "tx_hash": "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
                      "status": "failed",
                      "credited_amount": null,
                      "credited_currency": null,
                      "failure_code": "CHAIN_EXECUTION_FAILED",
                      "failure_message": "On-chain execution failed",
                      "created_at": 1794211380,
                      "updated_at": 1794211500,
                      "completed_at": null
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Return 200 after durably saving the event; process business logic asynchronously."
          }
        }
      }
    }
  }
}