{
	"openapi": "3.0.3",
	"info": {
		"title": "Tron Dealer V2 API — Wallet Management",
		"version": "2.0.0",
		"description": "API for automated wallet management across EVM networks (BSC, Ethereum, Polygon, Arbitrum, Base, Avalanche — USDT/USDC everywhere, plus PYUSD on Ethereum mainnet and the ARB token on Arbitrum), TRON (USDT TRC20 + native TRX), Solana (USDT-SPL, USDC-SPL, USDG-SPL + native SOL), Bitcoin (BTC native), Litecoin (LTC native), TON (USDT Jetton), and Stellar (native XLM + USDC, memo-based deposits on one shared address). Native coin deposits are also accepted on BSC (BNB), Ethereum mainnet (ETH) and Polygon (POL) — native ETH on Arbitrum/Base/Optimism and native AVAX are NOT deposit assets. Register as a client, assign deposit wallets, query balances and transaction history. Internal CRON endpoints handle blockchain scanning, webhook notifications, and fund sweeping.\n\n**Amount contract.** Across all chains and assets the `amount` field on webhook payloads is the **USD-equivalent value** at event time. For stablecoins (`USDT`, `USDC`, `PYUSD`) `amount` equals the on-chain amount 1:1. For native/volatile deposit assets (`BTC`, `LTC`, `TRX`, `SOL`, `BNB`, `ETH`, `POL`, `GRAM`, `XLM`, and the `ARB` ERC-20 token on Arbitrum), `amount_native` carries the on-chain unit and `price_usd` the spot used: `amount ≈ amount_native × price_usd`. The spot is frozen at detect time; if no USD price is available, the notification is deferred to the next cron tick — it is never sent with partial amount data. This lets merchants compare `amount` to `order.total` without per-asset branching.\n\n**Deprecated 2026-09-15:** Optimism."
	},
	"servers": [
		{
			"url": "/",
			"description": "Current server"
		}
	],
	"tags": [
		{
			"name": "Clients",
			"description": "Register new clients and manage client configuration (payout method, webhook)"
		},
		{
			"name": "Networks",
			"description": "Discover the chains and assets currently supported by V2"
		},
		{
			"name": "EVM Wallets",
			"description": "Assign EVM wallets, check balances, and view transaction history (BSC, ETH, POL, ARB, BASE, OPT, AVAX)"
		},
		{
			"name": "TRON Wallets",
			"description": "Assign TRON (TRC20) wallets, check TRX/USDT balances, and view USDT + native TRX deposit history"
		},
		{
			"name": "SOL Wallets",
			"description": "Assign Solana (Ed25519) wallets, check SOL/USDT-SPL/USDC-SPL/USDG-SPL balances, and view SPL + native SOL deposit history"
		},
		{
			"name": "BTC Wallets",
			"description": "Assign Bitcoin (P2WPKH) wallets, check confirmed/unconfirmed BTC balances, and view native BTC deposit history"
		},
		{
			"name": "LTC Wallets",
			"description": "Assign Litecoin (P2WPKH) wallets, check confirmed/unconfirmed LTC balances, and view native LTC deposit history"
		},
		{
			"name": "TON Wallets",
			"description": "Assign TON (WalletContractV4) wallets, check GRAM/USDT (Jetton) balances, and view USDT and native GRAM deposit history"
		},
		{
			"name": "XLM Wallets",
			"description": "Stellar deposits (native XLM and Circle USDC). Every XLM wallet is a **memo** on one shared deposit address: payers MUST include the memo (memo type ID) or pay the wallet's muxed `M...` address. Stellar finality is deterministic — a deposit is final in the ledger it lands in (1 confirmation)."
		},
		{
			"name": "Webhooks",
			"description": "Webhook notifications sent to your configured URL when deposits are detected, confirmed, or swept"
		}
	],
	"paths": {
		"/api/v2/clients/register-open": {
			"post": {
				"tags": [
					"Clients"
				],
				"summary": "Register a new client (public)",
				"description": "Creates a new client account and returns an API key. No authentication required — rate limited to **1 registration per IP per hour**.\n\nUse the returned `api_key` to authenticate all subsequent API requests via the `x-api-key` header.\n\nOptionally configure payout method and webhook notifications at registration time — or update them later via `PATCH /api/v2/clients/me`. All supported networks (BSC, ETH, Polygon, Arbitrum, Base) are enabled automatically for every client.",
				"operationId": "registerClient",
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/RegisterRequest"
							},
							"example": {
								"name": "My Business",
								"webhook_url": "https://example.com/webhooks/trondealer",
								"webhook_secret": "my-signing-secret",
								"payout_method": "wallet",
								"sweep_wallet_evm": "0x1234567890abcdef1234567890abcdef12345678",
								"sweep_wallet_tron": "TCsHYKC27np7cGAxJEq55DnsGysejpFF11"
							}
						}
					}
				},
				"responses": {
					"201": {
						"description": "Client created successfully",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"success": {
											"type": "boolean",
											"example": true
										},
										"client": {
											"$ref": "#/components/schemas/ClientFull"
										}
									}
								},
								"example": {
									"success": true,
									"client": {
										"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
										"name": "My Business",
										"api_key": "td_abc123def456...",
										"webhook_url": "https://example.com/webhooks/trondealer",
										"min_confirmations": null,
										"sweep_wallet_evm": "0x1234567890abcdef1234567890abcdef12345678",
										"sweep_wallet_tron": "TCsHYKC27np7cGAxJEq55DnsGysejpFF11",
										"payout_method": "wallet",
										"qvapay_account": null,
										"zelle_contact": null,
										"is_active": true,
										"created_at": "2026-04-07T12:00:00.000Z"
									}
								}
							}
						}
					},
					"400": {
						"$ref": "#/components/responses/BadRequest"
					},
					"429": {
						"description": "Rate limit exceeded — 1 registration per IP per hour",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								},
								"example": {
									"error": "Rate limit exceeded. You can register once per hour."
								}
							}
						}
					},
					"500": {
						"$ref": "#/components/responses/ServerError"
					}
				}
			}
		},
		"/api/v2/clients/me": {
			"get": {
				"tags": [
					"Clients"
				],
				"summary": "Get current client configuration",
				"description": "Returns the authenticated client's full configuration including payout method, webhook settings, and account metadata. The `webhook_secret` is masked — only the last 4 characters are returned.",
				"operationId": "getClientConfig",
				"security": [
					{
						"ApiKey": []
					}
				],
				"responses": {
					"200": {
						"description": "Client configuration retrieved",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"success": {
											"type": "boolean",
											"example": true
										},
										"client": {
											"$ref": "#/components/schemas/ClientConfig"
										}
									}
								},
								"example": {
									"success": true,
									"client": {
										"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
										"name": "My Business",
										"webhook_url": "https://example.com/webhooks/trondealer",
										"webhook_secret_masked": "****cret",
										"has_webhook_secret": true,
										"notify_confirmation_updates": false,
										"min_confirmations": 15,
										"sweep_wallet_evm": "0x1234567890abcdef1234567890abcdef12345678",
										"sweep_wallet_tron": "TCsHYKC27np7cGAxJEq55DnsGysejpFF11",
										"payout_method": "wallet",
										"qvapay_account": null,
										"zelle_contact": null,
										"created_at": "2026-04-07T12:00:00.000Z"
									}
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"500": {
						"$ref": "#/components/responses/ServerError"
					}
				}
			},
			"patch": {
				"tags": [
					"Clients"
				],
				"summary": "Update client configuration",
				"description": "Update one or more client settings. Include only the fields you want to change.\n\n**Payout method:** Set `payout_method` to `'wallet'`, `'qvapay'`, `'zelle'`, or `null`. Changing the payout method automatically clears the fields of the previous method.\n\n**Webhook:** Update `webhook_url` and `webhook_secret` independently. Set to `null` to remove.",
				"operationId": "updateClientConfig",
				"security": [
					{
						"ApiKey": []
					}
				],
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/UpdateConfigRequest"
							},
							"examples": {
								"switch_to_qvapay": {
									"summary": "Switch payout to QvaPay",
									"value": {
										"payout_method": "qvapay",
										"qvapay_account": "mi-cuenta@qvapay.com"
									}
								},
								"switch_to_wallet": {
									"summary": "Switch payout to crypto wallet",
									"value": {
										"payout_method": "wallet",
										"sweep_wallet_evm": "0x1234567890abcdef1234567890abcdef12345678",
										"sweep_wallet_tron": "TCsHYKC27np7cGAxJEq55DnsGysejpFF11"
									}
								},
								"update_webhook": {
									"summary": "Update webhook URL",
									"value": {
										"webhook_url": "https://example.com/new-webhook",
										"webhook_secret": "new-secret-123"
									}
								},
								"remove_webhook": {
									"summary": "Remove webhook",
									"value": {
										"webhook_url": null,
										"webhook_secret": null
									}
								},
								"enable_confirmation_updates": {
									"summary": "Enable confirmation-progress webhooks",
									"value": {
										"notify_confirmation_updates": true
									}
								}
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Configuration updated",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"success": {
											"type": "boolean",
											"example": true
										},
										"client": {
											"$ref": "#/components/schemas/ClientConfig"
										}
									}
								}
							}
						}
					},
					"400": {
						"$ref": "#/components/responses/BadRequest"
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"500": {
						"$ref": "#/components/responses/ServerError"
					}
				}
			}
		},
		"/api/v2/networks": {
			"get": {
				"tags": [
					"Networks"
				],
				"summary": "List supported networks and assets",
				"description": "Returns the canonical catalog of blockchains and assets that V2 supports. Public endpoint — no authentication required, response is cached for 5 minutes.\n\nIntegrations (e.g. the WooCommerce plugin) should consume this rather than hardcoding the list, so new networks become available without a client-side release.",
				"operationId": "listNetworks",
				"responses": {
					"200": {
						"description": "Catalog of supported networks",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"success": {
											"type": "boolean",
											"example": true
										},
										"networks": {
											"type": "array",
											"items": {
												"$ref": "#/components/schemas/NetworkInfo"
											}
										}
									}
								}
							}
						}
					}
				}
			}
		},
		"/api/v2/wallets/assign": {
			"post": {
				"tags": [
					"EVM Wallets"
				],
				"summary": "Assign a new EVM wallet",
				"description": "Generates a new EVM wallet and assigns it to the authenticated client. Optionally accepts a `label` for identification — if a wallet with the same label and `status='active'` already exists for this client, it is returned instead of creating a new one. Deactivated wallets are not reused.\n\nPass `single_use: true` to have the wallet automatically deactivated by the sweep cron after its first successful sweep — useful for high-volume integrations that want a bounded active wallet set.",
				"operationId": "assignWallet",
				"security": [
					{
						"ApiKey": []
					}
				],
				"requestBody": {
					"required": false,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/AssignRequest"
							},
							"example": {
								"label": "user-deposit-42"
							}
						}
					}
				},
				"responses": {
					"201": {
						"description": "Wallet created and assigned",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"success": {
											"type": "boolean",
											"example": true
										},
										"wallet": {
											"$ref": "#/components/schemas/AssignedWallet"
										}
									}
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"500": {
						"$ref": "#/components/responses/ServerError"
					}
				}
			}
		},
		"/api/v2/wallets/balance": {
			"post": {
				"tags": [
					"EVM Wallets"
				],
				"summary": "Get live wallet balances",
				"description": "Returns native token, USDT, and USDC balances for a wallet owned by the authenticated client (plus PYUSD on Ethereum mainnet and ARB on Arbitrum).",
				"operationId": "getWalletBalance",
				"security": [
					{
						"ApiKey": []
					}
				],
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/EvmBalanceRequest"
							},
							"example": {
								"address": "0x1234567890abcdef1234567890abcdef12345678",
								"network": "bsc"
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Balances retrieved",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"success": {
											"type": "boolean",
											"example": true
										},
										"wallet": {
											"$ref": "#/components/schemas/WalletInfo"
										},
										"balances": {
											"type": "object",
											"description": "Balances keyed by network — contains only the requested network (`eth` when `network` is omitted).",
											"additionalProperties": {
												"$ref": "#/components/schemas/Balances"
											},
											"example": {
												"bsc": {
													"BNB": "0.0042",
													"USDT": "150.50",
													"USDC": "75.00"
												}
											}
										}
									}
								}
							}
						}
					},
					"400": {
						"$ref": "#/components/responses/BadRequest"
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"500": {
						"$ref": "#/components/responses/ServerError"
					}
				}
			}
		},
		"/api/v2/wallets/transactions": {
			"post": {
				"tags": [
					"EVM Wallets"
				],
				"summary": "Get wallet transaction history",
				"description": "Returns paginated transaction history for a wallet owned by the authenticated client. Supports filtering by status and by asset (`USDT`, `USDC`, `PYUSD` on Ethereum mainnet, `ARB` on Arbitrum, and native `BNB`/`ETH`/`POL` where accepted). Native coin deposits are tracked on bsc (BNB), eth (ETH) and pol (POL) only — only direct transfers are detected (transfers made inside a contract call are not).",
				"operationId": "getWalletTransactions",
				"security": [
					{
						"ApiKey": []
					}
				],
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/TransactionsRequest"
							},
							"example": {
								"address": "0x1234567890abcdef1234567890abcdef12345678",
								"limit": 20,
								"offset": 0,
								"status": "confirmed"
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Transactions retrieved",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"success": {
											"type": "boolean",
											"example": true
										},
										"wallet": {
											"type": "object",
											"properties": {
												"address": {
													"type": "string"
												},
												"label": {
													"type": "string",
													"nullable": true
												}
											}
										},
										"total": {
											"type": "integer",
											"description": "Total number of matching transactions",
											"example": 42
										},
										"limit": {
											"type": "integer",
											"example": 20
										},
										"offset": {
											"type": "integer",
											"example": 0
										},
										"transactions": {
											"type": "array",
											"items": {
												"$ref": "#/components/schemas/Transaction"
											}
										}
									}
								}
							}
						}
					},
					"400": {
						"$ref": "#/components/responses/BadRequest"
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"500": {
						"$ref": "#/components/responses/ServerError"
					}
				}
			}
		},
		"/api/v2/wallets/check-hash": {
			"post": {
				"tags": [
					"EVM Wallets"
				],
				"summary": "Declare a deposit by transaction hash",
				"description": "Declare a deposit by transaction hash for a wallet you own. Use it when a payment reached one of your deposit addresses but no webhook arrived — typically because the wallet had been deactivated (120 days idle, or by you) before the customer paid. The transaction is fetched once; every leg that pays the wallet is recorded as `detected` and the normal confirm → webhook → sweep pipeline takes over. If the wallet was inactive it is reactivated (it counts against the active-wallets cap, 1000 by default; 429 `WALLET_CAP_REACHED` when full), but **no historical rescan is run** — declare each missed deposit by its own hash. Idempotent: repeating a hash returns `credited: true` with `new_transactions: 0`. A hash that exists but pays a different address returns `credited: false`. Rate limit: 5 calls per minute per client per subsystem → 429 `RATE_LIMITED` + `Retry-After`. On bsc/eth/pol native coin credits are detected too, including value moved inside a contract call (the scheduled scan only sees direct transfers).",
				"operationId": "checkWalletHash",
				"security": [
					{
						"ApiKey": []
					}
				],
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/EvmCheckHashRequest"
							},
							"example": {
								"network": "bsc",
								"address": "0x1234567890abcdef1234567890abcdef12345678",
								"tx_hash": "0x9f2c1d…"
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Transaction looked up. Check `credited` — a 200 does not by itself mean the wallet was paid.",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/CheckHashResponse"
								}
							}
						}
					},
					"400": {
						"description": "Malformed body, or the transaction could not be used: not found (still propagating, wrong chain), reverted/failed on-chain.",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								},
								"example": {
									"error": "Transaction not found on BSC"
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"429": {
						"description": "Rate limited (`RATE_LIMITED`, wait `Retry-After` seconds), or the wallet is inactive and the active-wallet cap is reached (`WALLET_CAP_REACHED`) — nothing was imported.",
						"headers": {
							"Retry-After": {
								"description": "Seconds until the window resets (RATE_LIMITED only)",
								"schema": {
									"type": "integer"
								}
							}
						},
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								},
								"example": {
									"error": "Rate limit exceeded: max 5 check-hash requests per minute",
									"code": "RATE_LIMITED",
									"retry_after": 42
								}
							}
						}
					},
					"500": {
						"$ref": "#/components/responses/ServerError"
					}
				}
			}
		},
		"/api/v2/tron/wallets/assign": {
			"post": {
				"tags": [
					"TRON Wallets"
				],
				"summary": "Assign a new TRON wallet",
				"description": "Generates a new TRON (TRC20) wallet and assigns it to the authenticated client. Optionally accepts a `label` for identification — if a wallet with the same label already exists for this client, it is returned instead of creating a new one.\n\nNew TRON wallets start as **unactivated** (`activated: false`). The TRON sweep cron lazily activates them with 20 TRX the first time funds need to be moved.",
				"operationId": "assignTronWallet",
				"security": [
					{
						"ApiKey": []
					}
				],
				"requestBody": {
					"required": false,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/AssignRequest"
							},
							"example": {
								"label": "user-deposit-42"
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Wallet matching the supplied label already exists — returned instead of creating a new one",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"success": {
											"type": "boolean",
											"example": true
										},
										"wallet": {
											"$ref": "#/components/schemas/AssignedTronWallet"
										}
									}
								}
							}
						}
					},
					"201": {
						"description": "New TRON wallet created and assigned",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"success": {
											"type": "boolean",
											"example": true
										},
										"wallet": {
											"$ref": "#/components/schemas/AssignedTronWallet"
										}
									}
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"500": {
						"$ref": "#/components/responses/ServerError"
					}
				}
			}
		},
		"/api/v2/tron/wallets/balance": {
			"post": {
				"tags": [
					"TRON Wallets"
				],
				"summary": "Get live TRON wallet balances",
				"description": "Returns live TRX and USDT (TRC20) balances for a TRON wallet owned by the authenticated client, plus the on-chain activation status. Each balance is reported as both the raw integer (smallest unit) and a human-readable string. V2 TRON accepts USDT (TRC20) and **native TRX** as deposit assets — USDC TRC20 is not tracked. TRX deposits below 2 TRX are ignored. Note: only direct TRX transfers are detected; TRX sent from inside a contract call (internal transactions) is not.",
				"operationId": "getTronWalletBalance",
				"security": [
					{
						"ApiKey": []
					}
				],
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/TronAddressRequest"
							},
							"example": {
								"address": "TCsHYKC27np7cGAxJEq55DnsGysejpFF11"
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Balances retrieved",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"success": {
											"type": "boolean",
											"example": true
										},
										"address": {
											"type": "string",
											"example": "TCsHYKC27np7cGAxJEq55DnsGysejpFF11"
										},
										"label": {
											"type": "string",
											"nullable": true
										},
										"activated": {
											"type": "boolean",
											"description": "Whether the TRON account is activated on-chain. Unactivated accounts can receive funds but cannot send."
										},
										"balances": {
											"$ref": "#/components/schemas/TronBalances"
										}
									}
								}
							}
						}
					},
					"400": {
						"$ref": "#/components/responses/BadRequest"
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"500": {
						"$ref": "#/components/responses/ServerError"
					}
				}
			}
		},
		"/api/v2/tron/wallets/transactions": {
			"post": {
				"tags": [
					"TRON Wallets"
				],
				"summary": "Get TRON transaction history",
				"description": "Returns recent USDT TRC20 and native TRX deposit transactions for the authenticated client. If `address` is provided, results are scoped to that wallet (which must belong to the client); otherwise all of the client's TRON transactions are returned. Optional `status` and `asset` (`USDT`/`TRX`) filters and `limit`/`offset` pagination (no total count returned — request `limit + 1` to detect more pages).",
				"operationId": "getTronWalletTransactions",
				"security": [
					{
						"ApiKey": []
					}
				],
				"requestBody": {
					"required": false,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/TronTransactionsRequest"
							},
							"example": {
								"address": "TCsHYKC27np7cGAxJEq55DnsGysejpFF11",
								"limit": 20,
								"offset": 0,
								"status": "confirmed"
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Transactions retrieved",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"success": {
											"type": "boolean",
											"example": true
										},
										"transactions": {
											"type": "array",
											"items": {
												"$ref": "#/components/schemas/TronTransaction"
											}
										}
									}
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"500": {
						"$ref": "#/components/responses/ServerError"
					}
				}
			}
		},
		"/api/v2/tron/wallets/check-hash": {
			"post": {
				"tags": [
					"TRON Wallets"
				],
				"summary": "Declare a TRON deposit by transaction id",
				"description": "Declare a deposit by transaction hash for a wallet you own. Use it when a payment reached one of your deposit addresses but no webhook arrived — typically because the wallet had been deactivated (120 days idle, or by you) before the customer paid. The transaction is fetched once; every leg that pays the wallet is recorded as `detected` and the normal confirm → webhook → sweep pipeline takes over. If the wallet was inactive it is reactivated (it counts against the active-wallets cap, 1000 by default; 429 `WALLET_CAP_REACHED` when full), but **no historical rescan is run** — declare each missed deposit by its own hash. Idempotent: repeating a hash returns `credited: true` with `new_transactions: 0`. A hash that exists but pays a different address returns `credited: false`. Rate limit: 5 calls per minute per client per subsystem → 429 `RATE_LIMITED` + `Retry-After`.",
				"operationId": "checkTronWalletHash",
				"security": [
					{
						"ApiKey": []
					}
				],
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/TronCheckHashRequest"
							},
							"example": {
								"address": "TCsHYKC27np7cGAxJEq55DnsGysejpFF11",
								"tx_hash": "6d5e0a…"
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Transaction looked up. Check `credited` — a 200 does not by itself mean the wallet was paid.",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/CheckHashResponse"
								}
							}
						}
					},
					"400": {
						"description": "Malformed body, or the transaction could not be used: not found (still propagating, wrong chain), reverted/failed on-chain.",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								},
								"example": {
									"error": "Transaction not found on BSC"
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"429": {
						"description": "Rate limited (`RATE_LIMITED`, wait `Retry-After` seconds), or the wallet is inactive and the active-wallet cap is reached (`WALLET_CAP_REACHED`) — nothing was imported.",
						"headers": {
							"Retry-After": {
								"description": "Seconds until the window resets (RATE_LIMITED only)",
								"schema": {
									"type": "integer"
								}
							}
						},
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								},
								"example": {
									"error": "Rate limit exceeded: max 5 check-hash requests per minute",
									"code": "RATE_LIMITED",
									"retry_after": 42
								}
							}
						}
					},
					"500": {
						"$ref": "#/components/responses/ServerError"
					}
				}
			}
		},
		"/api/v2/sol/wallets/assign": {
			"post": {
				"tags": [
					"SOL Wallets"
				],
				"summary": "Assign a new Solana wallet",
				"description": "Generates a new Solana (Ed25519) wallet and assigns it to the authenticated client. Optionally accepts a `label` for identification — if a wallet with the same label already exists for this client, it is returned instead of creating a new one.\n\n**Zero on-chain cost.** Solana wallets do not need activation. The Associated Token Accounts (ATAs) for USDT-SPL, USDC-SPL and USDG-SPL are created lazily by the payer on the first deposit, not by us at assign time.",
				"operationId": "assignSolWallet",
				"security": [
					{
						"ApiKey": []
					}
				],
				"requestBody": {
					"required": false,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/AssignRequest"
							},
							"example": {
								"label": "user-deposit-42"
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Wallet matching the supplied label already exists — returned instead of creating a new one",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"success": {
											"type": "boolean",
											"example": true
										},
										"wallet": {
											"$ref": "#/components/schemas/AssignedSolWallet"
										}
									}
								}
							}
						}
					},
					"201": {
						"description": "New Solana wallet created and assigned",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"success": {
											"type": "boolean",
											"example": true
										},
										"wallet": {
											"$ref": "#/components/schemas/AssignedSolWallet"
										}
									}
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"500": {
						"$ref": "#/components/responses/ServerError"
					}
				}
			}
		},
		"/api/v2/sol/wallets/balance": {
			"post": {
				"tags": [
					"SOL Wallets"
				],
				"summary": "Get live Solana wallet balances",
				"description": "Returns live SOL native, USDT-SPL, USDC-SPL, and USDG-SPL balances for a Solana wallet owned by the authenticated client. Each balance is reported as both raw integer (smallest unit) and a human-readable string.\n\n**Tokens whose ATA does not yet exist on-chain are reported as 0**, since SPL token accounts are created lazily by the first payer. **Native SOL is now accepted as a deposit asset** — deposits of at least 0.005 SOL are detected, confirmed and swept like SPL deposits (smaller amounts are ignored as dust).",
				"operationId": "getSolWalletBalance",
				"security": [
					{
						"ApiKey": []
					}
				],
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/SolAddressRequest"
							},
							"example": {
								"address": "5kQwVxYzABc1d2eF3gH4iJ5kL6mN7oP8qR9sTuVwXyZ1"
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Balances retrieved",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"success": {
											"type": "boolean",
											"example": true
										},
										"address": {
											"type": "string",
											"example": "5kQwVxYzABc1d2eF3gH4iJ5kL6mN7oP8qR9sTuVwXyZ1"
										},
										"label": {
											"type": "string",
											"nullable": true
										},
										"balances": {
											"$ref": "#/components/schemas/SolBalances"
										}
									}
								}
							}
						}
					},
					"400": {
						"$ref": "#/components/responses/BadRequest"
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"500": {
						"$ref": "#/components/responses/ServerError"
					}
				}
			}
		},
		"/api/v2/sol/wallets/transactions": {
			"post": {
				"tags": [
					"SOL Wallets"
				],
				"summary": "Get Solana transaction history",
				"description": "Returns recent USDT-SPL, USDC-SPL and native SOL deposit transactions for the authenticated client. If `address` is provided, results are scoped to that wallet (which must belong to the client); otherwise all of the client's Solana transactions are returned. Optional `status` and `asset` (`USDT`/`USDC`/`SOL`) filters and `limit`/`offset` pagination (no total count returned — request `limit + 1` to detect more pages).",
				"operationId": "getSolWalletTransactions",
				"security": [
					{
						"ApiKey": []
					}
				],
				"requestBody": {
					"required": false,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/SolTransactionsRequest"
							},
							"example": {
								"address": "5kQwVxYzABc1d2eF3gH4iJ5kL6mN7oP8qR9sTuVwXyZ1",
								"limit": 20,
								"offset": 0,
								"status": "confirmed"
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Transactions retrieved",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"success": {
											"type": "boolean",
											"example": true
										},
										"transactions": {
											"type": "array",
											"items": {
												"$ref": "#/components/schemas/SolTransaction"
											}
										}
									}
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"500": {
						"$ref": "#/components/responses/ServerError"
					}
				}
			}
		},
		"/api/v2/sol/wallets/check-hash": {
			"post": {
				"tags": [
					"SOL Wallets"
				],
				"summary": "Declare a Solana deposit by signature",
				"description": "Declare a deposit by transaction hash for a wallet you own. Use it when a payment reached one of your deposit addresses but no webhook arrived — typically because the wallet had been deactivated (120 days idle, or by you) before the customer paid. The transaction is fetched once; every leg that pays the wallet is recorded as `detected` and the normal confirm → webhook → sweep pipeline takes over. If the wallet was inactive it is reactivated (it counts against the active-wallets cap, 1000 by default; 429 `WALLET_CAP_REACHED` when full), but **no historical rescan is run** — declare each missed deposit by its own hash. Idempotent: repeating a hash returns `credited: true` with `new_transactions: 0`. A hash that exists but pays a different address returns `credited: false`. Rate limit: 5 calls per minute per client per subsystem → 429 `RATE_LIMITED` + `Retry-After`.",
				"operationId": "checkSolWalletHash",
				"security": [
					{
						"ApiKey": []
					}
				],
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/SolCheckHashRequest"
							},
							"example": {
								"address": "7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU",
								"tx_hash": "5UfDq7…"
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Transaction looked up. Check `credited` — a 200 does not by itself mean the wallet was paid.",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/CheckHashResponse"
								}
							}
						}
					},
					"400": {
						"description": "Malformed body, or the transaction could not be used: not found (still propagating, wrong chain), reverted/failed on-chain.",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								},
								"example": {
									"error": "Transaction not found on BSC"
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"429": {
						"description": "Rate limited (`RATE_LIMITED`, wait `Retry-After` seconds), or the wallet is inactive and the active-wallet cap is reached (`WALLET_CAP_REACHED`) — nothing was imported.",
						"headers": {
							"Retry-After": {
								"description": "Seconds until the window resets (RATE_LIMITED only)",
								"schema": {
									"type": "integer"
								}
							}
						},
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								},
								"example": {
									"error": "Rate limit exceeded: max 5 check-hash requests per minute",
									"code": "RATE_LIMITED",
									"retry_after": 42
								}
							}
						}
					},
					"500": {
						"$ref": "#/components/responses/ServerError"
					}
				}
			}
		},
		"/api/v2/btc/wallets/assign": {
			"post": {
				"tags": [
					"BTC Wallets"
				],
				"summary": "Assign a new Bitcoin wallet",
				"description": "Generates a new Bitcoin P2WPKH (native SegWit) wallet and assigns it to the authenticated client. Optionally accepts a `label` for identification — if an *active* wallet with the same label already exists for this client, it is returned instead of creating a new one.\n\n**Zero on-chain cost.** Bitcoin addresses need no activation or pre-funding. Deposits confirm after 2 blocks by default and are swept with a consolidating transaction where the wallet pays its own miner fee.",
				"operationId": "assignBtcWallet",
				"security": [
					{
						"ApiKey": []
					}
				],
				"requestBody": {
					"required": false,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/AssignRequest"
							},
							"example": {
								"label": "user-deposit-42"
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Wallet matching the supplied label already exists — returned instead of creating a new one",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"success": {
											"type": "boolean",
											"example": true
										},
										"wallet": {
											"$ref": "#/components/schemas/AssignedBtcWallet"
										}
									}
								}
							}
						}
					},
					"201": {
						"description": "New BTC wallet created and assigned",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"success": {
											"type": "boolean",
											"example": true
										},
										"wallet": {
											"$ref": "#/components/schemas/AssignedBtcWallet"
										}
									}
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"500": {
						"$ref": "#/components/responses/ServerError"
					}
				}
			}
		},
		"/api/v2/btc/wallets/balance": {
			"post": {
				"tags": [
					"BTC Wallets"
				],
				"summary": "Get BTC wallet balance",
				"description": "Returns the native BTC balance of a wallet owned by the authenticated client, split into confirmed and unconfirmed amounts and reported both in BTC and satoshis (computed from the tracked UTXO set).",
				"operationId": "getBtcWalletBalance",
				"security": [
					{
						"ApiKey": []
					}
				],
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/BtcAddressRequest"
							},
							"example": {
								"address": "bc1qw4lvtv08phk49cw2ucpvxhc8sy54ja2v9376k2"
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Balances retrieved",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"success": {
											"type": "boolean",
											"example": true
										},
										"address": {
											"type": "string",
											"example": "bc1qw4lvtv08phk49cw2ucpvxhc8sy54ja2v9376k2"
										},
										"label": {
											"type": "string",
											"nullable": true
										},
										"balances": {
											"$ref": "#/components/schemas/BtcBalances"
										}
									}
								}
							}
						}
					},
					"400": {
						"$ref": "#/components/responses/BadRequest"
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"500": {
						"$ref": "#/components/responses/ServerError"
					}
				}
			}
		},
		"/api/v2/btc/wallets/transactions": {
			"post": {
				"tags": [
					"BTC Wallets"
				],
				"summary": "List BTC deposit transactions",
				"description": "Paginated history of native BTC deposits for the authenticated client, newest first. Optionally filter by wallet `address` and lifecycle `status`. Each row is one transaction *output* — a deposit is uniquely identified by `(tx_hash, vout_index)`.",
				"operationId": "listBtcTransactions",
				"security": [
					{
						"ApiKey": []
					}
				],
				"requestBody": {
					"required": false,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/BtcTransactionsRequest"
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Transactions retrieved",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"success": {
											"type": "boolean",
											"example": true
										},
										"transactions": {
											"type": "array",
											"items": {
												"$ref": "#/components/schemas/BtcTransaction"
											}
										}
									}
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"500": {
						"$ref": "#/components/responses/ServerError"
					}
				}
			}
		},
		"/api/v2/btc/wallets/check-hash": {
			"post": {
				"tags": [
					"BTC Wallets"
				],
				"summary": "Declare a Bitcoin deposit by txid",
				"description": "Declare a deposit by transaction hash for a wallet you own. Use it when a payment reached one of your deposit addresses but no webhook arrived — typically because the wallet had been deactivated (120 days idle, or by you) before the customer paid. The transaction is fetched once; every leg that pays the wallet is recorded as `detected` and the normal confirm → webhook → sweep pipeline takes over. If the wallet was inactive it is reactivated (it counts against the active-wallets cap, 1000 by default; 429 `WALLET_CAP_REACHED` when full), but **no historical rescan is run** — declare each missed deposit by its own hash. Idempotent: repeating a hash returns `credited: true` with `new_transactions: 0`. A hash that exists but pays a different address returns `credited: false`. Rate limit: 5 calls per minute per client per subsystem → 429 `RATE_LIMITED` + `Retry-After`.",
				"operationId": "checkBtcWalletHash",
				"security": [
					{
						"ApiKey": []
					}
				],
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/BtcCheckHashRequest"
							},
							"example": {
								"address": "bc1q…",
								"tx_hash": "3a1f9c…"
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Transaction looked up. Check `credited` — a 200 does not by itself mean the wallet was paid.",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/CheckHashResponse"
								}
							}
						}
					},
					"400": {
						"description": "Malformed body, or the transaction could not be used: not found (still propagating, wrong chain), reverted/failed on-chain.",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								},
								"example": {
									"error": "Transaction not found on BSC"
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"429": {
						"description": "Rate limited (`RATE_LIMITED`, wait `Retry-After` seconds), or the wallet is inactive and the active-wallet cap is reached (`WALLET_CAP_REACHED`) — nothing was imported.",
						"headers": {
							"Retry-After": {
								"description": "Seconds until the window resets (RATE_LIMITED only)",
								"schema": {
									"type": "integer"
								}
							}
						},
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								},
								"example": {
									"error": "Rate limit exceeded: max 5 check-hash requests per minute",
									"code": "RATE_LIMITED",
									"retry_after": 42
								}
							}
						}
					},
					"500": {
						"$ref": "#/components/responses/ServerError"
					}
				}
			}
		},
		"/api/v2/ltc/wallets/assign": {
			"post": {
				"tags": [
					"LTC Wallets"
				],
				"summary": "Assign a new Litecoin wallet",
				"description": "Generates a new Litecoin P2WPKH (native SegWit) wallet and assigns it to the authenticated client. Optionally accepts a `label` for identification — if an *active* wallet with the same label already exists for this client, it is returned instead of creating a new one.\n\n**Zero on-chain cost.** Litecoin addresses need no activation or pre-funding. Deposits confirm after 6 blocks by default (~15 minutes at 2.5-minute block times) and are swept with a consolidating transaction where the wallet pays its own miner fee.",
				"operationId": "assignLtcWallet",
				"security": [
					{
						"ApiKey": []
					}
				],
				"requestBody": {
					"required": false,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/AssignRequest"
							},
							"example": {
								"label": "user-deposit-42"
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Wallet matching the supplied label already exists — returned instead of creating a new one",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"success": {
											"type": "boolean",
											"example": true
										},
										"wallet": {
											"$ref": "#/components/schemas/AssignedLtcWallet"
										}
									}
								}
							}
						}
					},
					"201": {
						"description": "New LTC wallet created and assigned",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"success": {
											"type": "boolean",
											"example": true
										},
										"wallet": {
											"$ref": "#/components/schemas/AssignedLtcWallet"
										}
									}
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"500": {
						"$ref": "#/components/responses/ServerError"
					}
				}
			}
		},
		"/api/v2/ltc/wallets/balance": {
			"post": {
				"tags": [
					"LTC Wallets"
				],
				"summary": "Get LTC wallet balance",
				"description": "Returns the native LTC balance of a wallet owned by the authenticated client, split into confirmed and unconfirmed amounts and reported both in LTC and litoshis (the `*_sats` fields — 1 litoshi = 1e-8 LTC), computed from the tracked UTXO set.",
				"operationId": "getLtcWalletBalance",
				"security": [
					{
						"ApiKey": []
					}
				],
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/LtcAddressRequest"
							},
							"example": {
								"address": "ltc1qtxu9nztx0cmm8kfz4fdwvya4pn9m2sf29ekvpul"
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Balances retrieved",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"success": {
											"type": "boolean",
											"example": true
										},
										"address": {
											"type": "string",
											"example": "ltc1qtxu9nztx0cmm8kfz4fdwvya4pn9m2sf29ekvpul"
										},
										"label": {
											"type": "string",
											"nullable": true
										},
										"balances": {
											"$ref": "#/components/schemas/LtcBalances"
										}
									}
								}
							}
						}
					},
					"400": {
						"$ref": "#/components/responses/BadRequest"
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"500": {
						"$ref": "#/components/responses/ServerError"
					}
				}
			}
		},
		"/api/v2/ltc/wallets/transactions": {
			"post": {
				"tags": [
					"LTC Wallets"
				],
				"summary": "List LTC deposit transactions",
				"description": "Paginated history of native LTC deposits for the authenticated client, newest first. Optionally filter by wallet `address` and lifecycle `status`. Each row is one transaction *output* — a deposit is uniquely identified by `(tx_hash, vout_index)`.",
				"operationId": "listLtcTransactions",
				"security": [
					{
						"ApiKey": []
					}
				],
				"requestBody": {
					"required": false,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/LtcTransactionsRequest"
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Transactions retrieved",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"success": {
											"type": "boolean",
											"example": true
										},
										"transactions": {
											"type": "array",
											"items": {
												"$ref": "#/components/schemas/LtcTransaction"
											}
										}
									}
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"500": {
						"$ref": "#/components/responses/ServerError"
					}
				}
			}
		},
		"/api/v2/ltc/wallets/check-hash": {
			"post": {
				"tags": [
					"LTC Wallets"
				],
				"summary": "Declare a Litecoin deposit by txid",
				"description": "Declare a deposit by transaction hash for a wallet you own. Use it when a payment reached one of your deposit addresses but no webhook arrived — typically because the wallet had been deactivated (120 days idle, or by you) before the customer paid. The transaction is fetched once; every leg that pays the wallet is recorded as `detected` and the normal confirm → webhook → sweep pipeline takes over. If the wallet was inactive it is reactivated (it counts against the active-wallets cap, 1000 by default; 429 `WALLET_CAP_REACHED` when full), but **no historical rescan is run** — declare each missed deposit by its own hash. Idempotent: repeating a hash returns `credited: true` with `new_transactions: 0`. A hash that exists but pays a different address returns `credited: false`. Rate limit: 5 calls per minute per client per subsystem → 429 `RATE_LIMITED` + `Retry-After`.",
				"operationId": "checkLtcWalletHash",
				"security": [
					{
						"ApiKey": []
					}
				],
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/LtcCheckHashRequest"
							},
							"example": {
								"address": "ltc1q…",
								"tx_hash": "b7c24e…"
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Transaction looked up. Check `credited` — a 200 does not by itself mean the wallet was paid.",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/CheckHashResponse"
								}
							}
						}
					},
					"400": {
						"description": "Malformed body, or the transaction could not be used: not found (still propagating, wrong chain), reverted/failed on-chain.",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								},
								"example": {
									"error": "Transaction not found on BSC"
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"429": {
						"description": "Rate limited (`RATE_LIMITED`, wait `Retry-After` seconds), or the wallet is inactive and the active-wallet cap is reached (`WALLET_CAP_REACHED`) — nothing was imported.",
						"headers": {
							"Retry-After": {
								"description": "Seconds until the window resets (RATE_LIMITED only)",
								"schema": {
									"type": "integer"
								}
							}
						},
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								},
								"example": {
									"error": "Rate limit exceeded: max 5 check-hash requests per minute",
									"code": "RATE_LIMITED",
									"retry_after": 42
								}
							}
						}
					},
					"500": {
						"$ref": "#/components/responses/ServerError"
					}
				}
			}
		},
		"/api/v2/ton/wallets/assign": {
			"post": {
				"tags": [
					"TON Wallets"
				],
				"summary": "Assign a new TON wallet",
				"description": "Generates a new TON wallet (WalletContractV4, Ed25519) and assigns it to the authenticated client. Optionally accepts a `label` for identification — if an *active* wallet with the same label already exists for this client, it is returned instead of creating a new one.\n\nThe wallet’s USDT **jetton wallet** address is derived once at assignment, so deposit scanning starts immediately. Send USDT (TEP-74 Jetton) to the returned `address` — the deposit lands on the derived jetton wallet and is detected automatically. Native TON sent to the address is treated as gas, not as a deposit asset.",
				"operationId": "assignTonWallet",
				"security": [
					{
						"ApiKey": []
					}
				],
				"requestBody": {
					"required": false,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/AssignRequest"
							},
							"example": {
								"label": "user-deposit-42"
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Wallet matching the supplied label already exists — returned instead of creating a new one",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"success": {
											"type": "boolean",
											"example": true
										},
										"wallet": {
											"$ref": "#/components/schemas/AssignedTonWallet"
										}
									}
								}
							}
						}
					},
					"201": {
						"description": "New TON wallet created and assigned",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"success": {
											"type": "boolean",
											"example": true
										},
										"wallet": {
											"$ref": "#/components/schemas/AssignedTonWallet"
										}
									}
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"500": {
						"$ref": "#/components/responses/ServerError"
					}
				}
			}
		},
		"/api/v2/ton/wallets/balance": {
			"post": {
				"tags": [
					"TON Wallets"
				],
				"summary": "Get live TON wallet balances",
				"description": "Returns live GRAM (TON network native coin) and USDT (Jetton) balances for a TON wallet owned by the authenticated client. Each balance is reported as both raw integer (nanograms for GRAM, 6-decimal raw for USDT) and a human-readable string.\n\n**Native GRAM is a deposit asset**: transfers of GRAM (0.4 GRAM minimum) to the wallet address are detected, notified and swept like any other deposit — webhook `amount` is USD at the detect-time spot, with `amount_native` and `price_usd` alongside. USDT sweeps use a fund-gas model (the main wallet tops up the deposit wallet with GRAM before it signs its own jetton transfer); GRAM sweeps drain the full balance in one MAX send and need no gas top-up. The `TON` balance key is a deprecated alias of `GRAM`, kept for backward compatibility.",
				"operationId": "getTonWalletBalance",
				"security": [
					{
						"ApiKey": []
					}
				],
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/TonAddressRequest"
							},
							"example": {
								"address": "UQAkEWzRLUUEygDpTzbcDsM6V4Wm65DZTcBgw0sFcj-VHJtu"
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Balances retrieved",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"success": {
											"type": "boolean",
											"example": true
										},
										"address": {
											"type": "string",
											"example": "UQAkEWzRLUUEygDpTzbcDsM6V4Wm65DZTcBgw0sFcj-VHJtu"
										},
										"label": {
											"type": "string",
											"nullable": true
										},
										"balances": {
											"$ref": "#/components/schemas/TonBalances"
										}
									}
								}
							}
						}
					},
					"400": {
						"$ref": "#/components/responses/BadRequest"
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"429": {
						"$ref": "#/components/responses/TooManyRequests"
					},
					"500": {
						"$ref": "#/components/responses/ServerError"
					}
				}
			}
		},
		"/api/v2/ton/wallets/transactions": {
			"post": {
				"tags": [
					"TON Wallets"
				],
				"summary": "List TON deposit transactions",
				"description": "Paginated history of USDT (Jetton) and native GRAM deposits for the authenticated client, newest first. Optionally filter by wallet `address` (the exact string returned at assignment) and lifecycle `status`. A deposit is uniquely identified by `(tx_hash, lt)` — the hash and account logical time of the receiving account's inbound transfer (the derived jetton wallet for USDT, the wallet address itself for GRAM).",
				"operationId": "listTonTransactions",
				"security": [
					{
						"ApiKey": []
					}
				],
				"requestBody": {
					"required": false,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/TonTransactionsRequest"
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Transactions retrieved",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"success": {
											"type": "boolean",
											"example": true
										},
										"transactions": {
											"type": "array",
											"items": {
												"$ref": "#/components/schemas/TonTransaction"
											}
										}
									}
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"500": {
						"$ref": "#/components/responses/ServerError"
					}
				}
			}
		},
		"/api/v2/ton/wallets/check-hash": {
			"post": {
				"tags": [
					"TON Wallets"
				],
				"summary": "Declare a TON deposit by transaction hash",
				"description": "Declare a deposit by transaction hash for a wallet you own. Use it when a payment reached one of your deposit addresses but no webhook arrived — typically because the wallet had been deactivated (120 days idle, or by you) before the customer paid. The transaction is fetched once; every leg that pays the wallet is recorded as `detected` and the normal confirm → webhook → sweep pipeline takes over. If the wallet was inactive it is reactivated (it counts against the active-wallets cap, 1000 by default; 429 `WALLET_CAP_REACHED` when full), but **no historical rescan is run** — declare each missed deposit by its own hash. Idempotent: repeating a hash returns `credited: true` with `new_transactions: 0`. A hash that exists but pays a different address returns `credited: false`. Rate limit: 5 calls per minute per client per subsystem → 429 `RATE_LIMITED` + `Retry-After`.",
				"operationId": "checkTonWalletHash",
				"security": [
					{
						"ApiKey": []
					}
				],
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/TonCheckHashRequest"
							},
							"example": {
								"address": "UQ…",
								"tx_hash": "e4a93b…"
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Transaction looked up. Check `credited` — a 200 does not by itself mean the wallet was paid.",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/CheckHashResponse"
								}
							}
						}
					},
					"400": {
						"description": "Malformed body, or the transaction could not be used: not found (still propagating, wrong chain), reverted/failed on-chain.",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								},
								"example": {
									"error": "Transaction not found on BSC"
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"429": {
						"description": "Rate limited (`RATE_LIMITED`, wait `Retry-After` seconds), or the wallet is inactive and the active-wallet cap is reached (`WALLET_CAP_REACHED`) — nothing was imported.",
						"headers": {
							"Retry-After": {
								"description": "Seconds until the window resets (RATE_LIMITED only)",
								"schema": {
									"type": "integer"
								}
							}
						},
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								},
								"example": {
									"error": "Rate limit exceeded: max 5 check-hash requests per minute",
									"code": "RATE_LIMITED",
									"retry_after": 42
								}
							}
						}
					},
					"500": {
						"$ref": "#/components/responses/ServerError"
					}
				}
			}
		},
		"/webhooks/transaction.incoming": {
			"post": {
				"tags": [
					"Webhooks"
				],
				"summary": "transaction.incoming — Deposit detected",
				"description": "Sent to your `webhook_url` as soon as a deposit is detected on-chain but **before** it reaches the minimum confirmations threshold. Use this for showing pending/incoming deposits in your UI.\n\nNative coin deposits (LTC, TRX, SOL, BNB, ETH, POL) follow the same payload shape as BTC: `amount` is the USD equivalent, `amount_native` the on-chain amount, and `price_usd` the spot frozen at detect time. If no USD price is available the notification is deferred to the next tick — never sent partial.\n\n**Delivery:** POST to your webhook URL with JSON body. Up to 1 retry.\n\n**Signature:** If you have a `webhook_secret` configured, the request includes an `X-Signature-256` header with an HMAC-SHA256 signature: `sha256=<hex>`. Compute `HMAC-SHA256(webhook_secret, raw_body)` and compare to verify authenticity.",
				"operationId": "webhookIncoming",
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/WebhookPayload"
							},
							"examples": {
								"stablecoin": {
									"summary": "USDT on BSC (stablecoin)",
									"value": {
										"event": "transaction.incoming",
										"timestamp": "2026-03-30T14:22:01.000Z",
										"data": {
											"tx_hash": "0xabc123def456789abc123def456789abc123def456789abc123def456789abcd",
											"block_number": 48123456,
											"from_address": "0x742d35Cc6634C0532925a3b844Bc9e7595f2bD18",
											"to_address": "0xAbC1234567890DEF1234567890abcdef12345678",
											"asset": "USDT",
											"amount": "150.50",
											"amount_native": "150.50",
											"price_usd": 1,
											"confirmations": 3,
											"wallet_label": "user-deposit-42",
											"network": "bsc"
										}
									}
								},
								"btc": {
									"summary": "BTC native (non-stablecoin) — LTC deposits use the identical payload with asset \"LTC\" / network \"ltc\"",
									"value": {
										"event": "transaction.incoming",
										"timestamp": "2026-05-22T19:48:07.000Z",
										"data": {
											"tx_hash": "e9180ce7ad9d29887e7567f00d0f02765750e323c903708a06bbc84f7641b50b",
											"vout_index": 0,
											"block_number": 950596,
											"from_address": null,
											"to_address": "bc1q29q5clx4ahkelqgfk60nry7wtl8su2yh4k77fl",
											"asset": "BTC",
											"amount": "39.20",
											"amount_native": "0.00052000",
											"price_usd": 75391,
											"confirmations": 1,
											"wallet_label": "user-deposit-42",
											"network": "btc"
										}
									}
								},
								"trx_native": {
									"summary": "TRX native — TRX, SOL, BNB, ETH and POL native deposits all follow this BTC-style payload (USD `amount` + `amount_native` + `price_usd`)",
									"value": {
										"event": "transaction.incoming",
										"timestamp": "2026-07-01T09:12:44.000Z",
										"data": {
											"tx_id": "abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789",
											"block_number": 68123456,
											"from_address": "TVj7RNVHy6thbtKBuM9e2DeR7mF7mZxCJ4",
											"to_address": "TCsHYKC27np7cGAxJEq55DnsGysejpFF11",
											"asset": "TRX",
											"amount": "36.75",
											"amount_native": "120.500000",
											"price_usd": 0.305,
											"confirmations": 3,
											"wallet_label": "user-deposit-42",
											"network": "tron"
										}
									}
								}
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Your server should return any 2xx status to acknowledge receipt. Non-2xx responses or timeouts (10s) are treated as failures."
					}
				}
			}
		},
		"/webhooks/transaction.confirmation_update": {
			"post": {
				"tags": [
					"Webhooks"
				],
				"summary": "transaction.confirmation_update — Confirmation progress (opt-in)",
				"description": "Sent to your `webhook_url` each time a pending deposit's confirmation count advances, so you can render a live progress indicator (`confirmations / min_confirmations`). Disabled by default — enable per client with `\"notify_confirmation_updates\": true` via `PATCH /api/v2/clients/me`. Available on the EVM networks, Bitcoin and Litecoin (where multi-block confirmation targets — 2 confs at ~10 min/block on Bitcoin, 6 confs at ~2.5 min/block on Litecoin — make progress genuinely informative); other chains confirm in 1-2 blocks and never emit it.\n\nThe payload matches the deposit events plus a `min_confirmations` field (the target count for this deposit).\n\n**Delivery:** fire-and-forget. No retries, missed updates are not re-sent, and ordering relative to `transaction.confirmed` is NOT guaranteed — an update can arrive after the confirmed event. Treat it as cosmetic: render the highest confirmation count seen and stop updating once `transaction.confirmed` arrives. Never credit balances from this event.\n\n**Signature:** If you have a `webhook_secret` configured, the request includes an `X-Signature-256` header with an HMAC-SHA256 signature: `sha256=<hex>`.",
				"operationId": "webhookConfirmationUpdate",
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/WebhookPayload"
							},
							"examples": {
								"btc": {
									"summary": "BTC 1 of 2 confirmations",
									"value": {
										"event": "transaction.confirmation_update",
										"timestamp": "2026-05-22T19:58:07.000Z",
										"data": {
											"tx_hash": "e9180ce7ad9d29887e7567f00d0f02765750e323c903708a06bbc84f7641b50b",
											"vout_index": 0,
											"block_number": 950596,
											"from_address": null,
											"to_address": "bc1q29q5clx4ahkelqgfk60nry7wtl8su2yh4k77fl",
											"asset": "BTC",
											"amount": "39.20",
											"amount_native": "0.00052000",
											"price_usd": 75391,
											"confirmations": 1,
											"min_confirmations": 2,
											"wallet_label": "user-deposit-42",
											"network": "btc"
										}
									}
								},
								"evm": {
									"summary": "USDT on ETH, 6 of 10 confirmations",
									"value": {
										"event": "transaction.confirmation_update",
										"timestamp": "2026-03-30T14:23:31.000Z",
										"data": {
											"tx_hash": "0xabc123def456789abc123def456789abc123def456789abc123def456789abcd",
											"block_number": 22123456,
											"from_address": "0x742d35Cc6634C0532925a3b844Bc9e7595f2bD18",
											"to_address": "0xAbC1234567890DEF1234567890abcdef12345678",
											"asset": "USDT",
											"amount": "150.50",
											"amount_native": "150.50",
											"price_usd": 1,
											"confirmations": 6,
											"min_confirmations": 10,
											"wallet_label": "user-deposit-42",
											"network": "eth"
										}
									}
								}
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Your server should return any 2xx status to acknowledge receipt. Responses are ignored — delivery is fire-and-forget with no retries."
					}
				}
			}
		},
		"/webhooks/transaction.confirmed": {
			"post": {
				"tags": [
					"Webhooks"
				],
				"summary": "transaction.confirmed — Deposit confirmed",
				"description": "Sent to your `webhook_url` once a deposit reaches the minimum confirmations threshold (default: 15 blocks). This is the primary event for crediting user balances.\n\n**Delivery:** POST to your webhook URL with JSON body. Up to 3 attempts. After 3 failed attempts, the transaction is marked as `notified` regardless.\n\n**Signature:** If you have a `webhook_secret` configured, the request includes an `X-Signature-256` header with an HMAC-SHA256 signature: `sha256=<hex>`. Compute `HMAC-SHA256(webhook_secret, raw_body)` and compare to verify authenticity.\n\n**Transaction lifecycle after confirmation:** `confirmed` → `notified` (webhook sent) → `swept` (funds moved to main wallet).",
				"operationId": "webhookConfirmed",
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/WebhookPayload"
							},
							"examples": {
								"stablecoin": {
									"summary": "USDT on BSC (stablecoin)",
									"value": {
										"event": "transaction.confirmed",
										"timestamp": "2026-03-30T14:25:30.000Z",
										"data": {
											"tx_hash": "0xabc123def456789abc123def456789abc123def456789abc123def456789abcd",
											"block_number": 48123456,
											"from_address": "0x742d35Cc6634C0532925a3b844Bc9e7595f2bD18",
											"to_address": "0xAbC1234567890DEF1234567890abcdef12345678",
											"asset": "USDT",
											"amount": "150.50",
											"amount_native": "150.50",
											"price_usd": 1,
											"confirmations": 15,
											"wallet_label": "user-deposit-42",
											"network": "bsc"
										}
									}
								},
								"btc": {
									"summary": "BTC native (non-stablecoin) — confirmed",
									"value": {
										"event": "transaction.confirmed",
										"timestamp": "2026-05-22T20:08:14.000Z",
										"data": {
											"tx_hash": "e9180ce7ad9d29887e7567f00d0f02765750e323c903708a06bbc84f7641b50b",
											"vout_index": 0,
											"block_number": 950596,
											"from_address": null,
											"to_address": "bc1q29q5clx4ahkelqgfk60nry7wtl8su2yh4k77fl",
											"asset": "BTC",
											"amount": "39.20",
											"amount_native": "0.00052000",
											"price_usd": 75391,
											"confirmations": 2,
											"wallet_label": "user-deposit-42",
											"network": "btc"
										}
									}
								}
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Your server should return any 2xx status to acknowledge receipt. Non-2xx responses or timeouts (10s) are treated as failures and will be retried (up to 3 attempts)."
					}
				}
			}
		},
		"/webhooks/transaction.swept": {
			"post": {
				"tags": [
					"Webhooks"
				],
				"summary": "transaction.swept — Funds swept to destination",
				"description": "Sent best-effort to your `webhook_url` after a confirmed deposit has been swept on-chain to your configured destination (your `sweep_wallet_evm` / `sweep_wallet_tron` when `payout_method='wallet'`, or the platform main wallet otherwise).\n\nUseful for reconciling on-chain custody movements with your internal ledger. The payload references the original deposit(s) via `source_tx_hashes` and reports the on-chain sweep transaction (`sweep_tx_hash`) and any optional fee transaction (`fee_tx_hash`).\n\n**Delivery:** Best-effort — fired once from the sweep cron. **No retry queue** (sweep cron runs every 10 minutes; missed notifications are not re-attempted).\n\n**Signature:** If you have a `webhook_secret` configured, the request includes an `X-Signature-256` header with an HMAC-SHA256 signature: `sha256=<hex>`.",
				"operationId": "webhookSwept",
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/WebhookSweptPayload"
							},
							"examples": {
								"evm_sweep": {
									"summary": "EVM USDT sweep",
									"value": {
										"event": "transaction.swept",
										"timestamp": "2026-03-30T14:35:12.000Z",
										"data": {
											"sweep_tx_hash": "0xfff111222333444555666777888999aaabbbcccdddeeefff111222333444555",
											"fee_tx_hash": null,
											"source_tx_hashes": [
												"0xabc123def456789abc123def456789abc123def456789abc123def456789abcd"
											],
											"asset": "USDT",
											"amount": "150.50",
											"amount_native": "150.50",
											"gross_amount": "150.50",
											"gross_amount_native": "150.50",
											"fee_amount": null,
											"fee_amount_native": null,
											"price_usd": 1,
											"destination": "0x9999AAAAbbbbCCCCddddEEEEffff000011112222",
											"wallet_address": "0xAbC1234567890DEF1234567890abcdef12345678",
											"wallet_label": "user-deposit-42",
											"network": "bsc"
										}
									}
								},
								"tron_sweep": {
									"summary": "TRON USDT sweep with payout fee",
									"value": {
										"event": "transaction.swept",
										"timestamp": "2026-03-30T14:36:00.000Z",
										"data": {
											"sweep_tx_hash": "9b8c7a6d5e4f3a2b1c0d9e8f7a6b5c4d3e2f1a0b9c8d7e6f5a4b3c2d1e0f9a8b",
											"fee_tx_hash": "1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b",
											"source_tx_hashes": [
												"abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789"
											],
											"asset": "USDT",
											"amount": "99.10",
											"amount_native": "99.10",
											"gross_amount": "100.00",
											"gross_amount_native": "100.00",
											"fee_amount": "0.90",
											"fee_amount_native": "0.90",
											"price_usd": 1,
											"destination": "TCsHYKC27np7cGAxJEq55DnsGysejpFF11",
											"wallet_address": "TVj7RNVHy6thbtKBuM9e2DeR7mF7mZxCJ4",
											"wallet_label": "user-deposit-42",
											"network": "tron"
										}
									}
								},
								"btc_sweep": {
									"summary": "BTC native sweep (non-stablecoin) — LTC sweeps use the identical payload with asset \"LTC\" / network \"ltc\"",
									"value": {
										"event": "transaction.swept",
										"timestamp": "2026-05-22T20:30:00.000Z",
										"data": {
											"sweep_tx_hash": "abc1234567890def1234567890abc1234567890def1234567890abc1234567",
											"fee_tx_hash": null,
											"source_tx_hashes": [
												"e9180ce7ad9d29887e7567f00d0f02765750e323c903708a06bbc84f7641b50b:0"
											],
											"asset": "BTC",
											"amount": "39.05",
											"amount_native": "0.00051800",
											"gross_amount": "39.20",
											"gross_amount_native": "0.00052000",
											"fee_amount": null,
											"fee_amount_native": null,
											"price_usd": 75391,
											"destination": "bc1qmainwalletxxxxxxxxxxxxxxxxxxxxxxxxxxx",
											"wallet_address": "bc1q29q5clx4ahkelqgfk60nry7wtl8su2yh4k77fl",
											"wallet_label": "user-deposit-42",
											"network": "btc"
										}
									}
								}
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Your server should return any 2xx status to acknowledge receipt. Non-2xx responses are logged but not retried."
					}
				}
			}
		},
		"/api/v2/xlm/wallets/assign": {
			"post": {
				"tags": [
					"XLM Wallets"
				],
				"summary": "Assign a new Stellar (memo) wallet",
				"description": "Creates a Stellar deposit wallet for the authenticated client. Stellar wallets are **memos on one shared deposit address**: the response carries the shared `address` (G...), the wallet's `memo` (u64 decimal string, memo type ID) and the equivalent `muxed_address` (M...).\n\n**The memo is mandatory.** A payer must send XLM or USDC to `address` with memo type ID = `memo`, or pay `muxed_address` (which embeds the memo). A payment to the plain address without the memo cannot be attributed and is held for manual review. Accepted assets: native XLM (minimum 2 XLM) and Circle USDC (issuer `GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN`, minimum 0.50). Smaller payments are ignored.\n\nIdempotent by label: if an *active* wallet with the same `label` exists it is returned (200). `single_use: true` marks a checkout-style wallet that is deactivated after its first sweep (and after 7 days if never paid). A deposit to the memo is credited even if the wallet was deactivated meanwhile.",
				"operationId": "assignXlmWallet",
				"security": [
					{
						"ApiKey": []
					}
				],
				"requestBody": {
					"required": false,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/AssignRequest"
							},
							"example": {
								"label": "5f0c8a7e-1d2b-4c3a-9e8f-7a6b5c4d3e2f",
								"single_use": true
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Wallet matching the supplied label already exists — returned instead of creating a new one",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"success": {
											"type": "boolean",
											"example": true
										},
										"wallet": {
											"$ref": "#/components/schemas/AssignedXlmWallet"
										}
									}
								}
							}
						}
					},
					"201": {
						"description": "New Stellar memo wallet created",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"success": {
											"type": "boolean",
											"example": true
										},
										"wallet": {
											"$ref": "#/components/schemas/AssignedXlmWallet"
										}
									}
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"500": {
						"$ref": "#/components/responses/ServerError"
					}
				}
			}
		},
		"/api/v2/xlm/wallets/balance": {
			"post": {
				"tags": [
					"XLM Wallets"
				],
				"summary": "Get a Stellar wallet's unswept balance",
				"description": "Every Stellar wallet shares one on-chain account, so there is no per-wallet chain balance. This returns the deposits credited to the wallet's memo that have **not been swept yet**, per asset (XLM and USDC, raw stroops + human string). No RPC call is made. Rate limited like every balance route (`BALANCE_RATE_LIMIT_PER_MIN`, default 1/min per client per subsystem → 429 `RATE_LIMITED`).",
				"operationId": "getXlmWalletBalance",
				"security": [
					{
						"ApiKey": []
					}
				],
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/XlmWalletKeyRequest"
							},
							"example": {
								"memo": "1234567890123456789"
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Balance retrieved",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"success": {
											"type": "boolean",
											"example": true
										},
										"address": {
											"type": "string",
											"example": "GCJAXR32J2VAFVCX4G32O52XNMT5XSKHOJ7V7XJE7CHIP3ZHU365LQAM"
										},
										"memo": {
											"type": "string",
											"example": "1234567890123456789"
										},
										"memo_type": {
											"type": "string",
											"enum": [
												"id"
											]
										},
										"muxed_address": {
											"type": "string"
										},
										"label": {
											"type": "string",
											"nullable": true
										},
										"balance_kind": {
											"type": "string",
											"enum": [
												"unswept_deposits"
											]
										},
										"balances": {
											"$ref": "#/components/schemas/XlmBalances"
										}
									}
								}
							}
						}
					},
					"400": {
						"description": "Missing/invalid memo or muxed_address (the shared G address alone is rejected).",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								}
							}
						}
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"429": {
						"description": "Rate limited (`RATE_LIMITED`)."
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"500": {
						"$ref": "#/components/responses/ServerError"
					}
				}
			}
		},
		"/api/v2/xlm/wallets/transactions": {
			"post": {
				"tags": [
					"XLM Wallets"
				],
				"summary": "List Stellar deposit transactions",
				"description": "Paginated XLM and USDC deposits for the authenticated client, newest first. Optionally filter by wallet (`memo` or `muxed_address`) and lifecycle `status`. A Stellar deposit is final in the ledger it closes in, so `confirmations` is always 1.",
				"operationId": "listXlmTransactions",
				"security": [
					{
						"ApiKey": []
					}
				],
				"requestBody": {
					"required": false,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/XlmTransactionsRequest"
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Transactions retrieved",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"success": {
											"type": "boolean",
											"example": true
										},
										"transactions": {
											"type": "array",
											"items": {
												"$ref": "#/components/schemas/XlmTransaction"
											}
										}
									}
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"500": {
						"$ref": "#/components/responses/ServerError"
					}
				}
			}
		},
		"/api/v2/xlm/wallets/check-hash": {
			"post": {
				"tags": [
					"XLM Wallets"
				],
				"summary": "Declare a Stellar deposit by transaction hash",
				"description": "Declare a deposit by transaction hash for a Stellar wallet you own, identified by its `memo` (or `muxed_address`) — never by the shared address. The transaction is read from the Stellar RPC, which keeps about **7 days** of history; older hashes return 400. Only transfers to the deposit address that carry this wallet's memo are credited. Use it when a payment reached one of your deposit addresses but no webhook arrived — typically because the wallet had been deactivated (120 days idle, or by you) before the customer paid. The transaction is fetched once; every leg that pays the wallet is recorded as `detected` and the normal confirm → webhook → sweep pipeline takes over. If the wallet was inactive it is reactivated (it counts against the active-wallets cap, 1000 by default; 429 `WALLET_CAP_REACHED` when full), but **no historical rescan is run** — declare each missed deposit by its own hash. Idempotent: repeating a hash returns `credited: true` with `new_transactions: 0`. A hash that exists but pays a different address returns `credited: false`. Rate limit: 5 calls per minute per client per subsystem → 429 `RATE_LIMITED` + `Retry-After`.",
				"operationId": "checkXlmWalletHash",
				"security": [
					{
						"ApiKey": []
					}
				],
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"$ref": "#/components/schemas/XlmCheckHashRequest"
							},
							"example": {
								"memo": "1234567890123456789",
								"tx_hash": "7778651d30ae7290f63ee6864cf2f725638fa6e8d989feb9090a2dee02c45cff"
							}
						}
					}
				},
				"responses": {
					"200": {
						"description": "Transaction looked up. Check `credited` — a 200 does not by itself mean the wallet was paid.",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/CheckHashResponse"
								}
							}
						}
					},
					"400": {
						"description": "Malformed body, or the transaction could not be used: not found (still propagating, wrong chain), reverted/failed on-chain.",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								},
								"example": {
									"error": "Transaction not found on BSC"
								}
							}
						}
					},
					"401": {
						"$ref": "#/components/responses/Unauthorized"
					},
					"403": {
						"$ref": "#/components/responses/Forbidden"
					},
					"404": {
						"$ref": "#/components/responses/NotFound"
					},
					"429": {
						"description": "Rate limited (`RATE_LIMITED`, wait `Retry-After` seconds), or the wallet is inactive and the active-wallet cap is reached (`WALLET_CAP_REACHED`) — nothing was imported.",
						"headers": {
							"Retry-After": {
								"description": "Seconds until the window resets (RATE_LIMITED only)",
								"schema": {
									"type": "integer"
								}
							}
						},
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ErrorResponse"
								},
								"example": {
									"error": "Rate limit exceeded: max 5 check-hash requests per minute",
									"code": "RATE_LIMITED",
									"retry_after": 42
								}
							}
						}
					},
					"500": {
						"$ref": "#/components/responses/ServerError"
					}
				}
			}
		}
	},
	"components": {
		"securitySchemes": {
			"ApiKey": {
				"type": "apiKey",
				"in": "header",
				"name": "x-api-key",
				"description": "Client API key provided during registration"
			}
		},
		"schemas": {
			"RegisterRequest": {
				"type": "object",
				"required": [
					"name"
				],
				"properties": {
					"name": {
						"type": "string",
						"description": "Client/business name",
						"minLength": 1,
						"maxLength": 100,
						"example": "My Business"
					},
					"webhook_url": {
						"type": "string",
						"format": "uri",
						"nullable": true,
						"description": "HTTPS URL to receive webhook notifications"
					},
					"webhook_secret": {
						"type": "string",
						"nullable": true,
						"maxLength": 256,
						"description": "Secret for HMAC-SHA256 webhook signature verification"
					},
					"min_confirmations": {
						"type": "integer",
						"minimum": 1,
						"maximum": 100,
						"nullable": true,
						"description": "Blocks to wait before confirming a transaction (default: network-specific)"
					},
					"payout_method": {
						"type": "string",
						"enum": [
							"wallet",
							"qvapay",
							"zelle"
						],
						"nullable": true,
						"description": "How to receive swept funds"
					},
					"sweep_wallet_evm": {
						"type": "string",
						"nullable": true,
						"description": "EVM address (0x...) to sweep funds to on EVM chains (BSC, ETH, POL, ARB, BASE, OPT, AVAX). When payout_method is 'wallet', at least one of sweep_wallet_evm or sweep_wallet_tron is required."
					},
					"sweep_wallet_tron": {
						"type": "string",
						"nullable": true,
						"description": "TRON Base58 address (T...) to sweep funds to on TRON. When payout_method is 'wallet', at least one of sweep_wallet_evm or sweep_wallet_tron is required."
					},
					"sweep_wallet": {
						"type": "string",
						"nullable": true,
						"deprecated": true,
						"description": "DEPRECATED — alias of sweep_wallet_evm kept for backwards compatibility. New integrations should send sweep_wallet_evm and/or sweep_wallet_tron explicitly."
					},
					"qvapay_account": {
						"type": "string",
						"nullable": true,
						"minLength": 2,
						"maxLength": 100,
						"description": "QvaPay account identifier (required when payout_method is 'qvapay')"
					},
					"zelle_contact": {
						"type": "string",
						"nullable": true,
						"minLength": 2,
						"maxLength": 100,
						"description": "Zelle contact info (required when payout_method is 'zelle')"
					}
				}
			},
			"ClientFull": {
				"type": "object",
				"description": "Full client object returned at registration (includes api_key).",
				"properties": {
					"id": {
						"type": "string",
						"format": "uuid"
					},
					"name": {
						"type": "string"
					},
					"api_key": {
						"type": "string",
						"description": "API key for authenticating requests. Store securely — only returned at registration.",
						"example": "td_abc123def456..."
					},
					"webhook_url": {
						"type": "string",
						"nullable": true
					},
					"min_confirmations": {
						"type": "integer",
						"nullable": true
					},
					"sweep_wallet_evm": {
						"type": "string",
						"nullable": true,
						"description": "EVM destination wallet (0x...) used by EVM sweep cron"
					},
					"sweep_wallet_tron": {
						"type": "string",
						"nullable": true,
						"description": "TRON destination wallet (T...) used by TRON sweep cron"
					},
					"payout_method": {
						"type": "string",
						"enum": [
							"wallet",
							"qvapay",
							"zelle"
						],
						"nullable": true
					},
					"qvapay_account": {
						"type": "string",
						"nullable": true
					},
					"zelle_contact": {
						"type": "string",
						"nullable": true
					},
					"is_active": {
						"type": "boolean"
					},
					"created_at": {
						"type": "string",
						"format": "date-time"
					}
				}
			},
			"ClientConfig": {
				"type": "object",
				"description": "Client configuration returned by GET/PATCH /clients/me. The webhook_secret is masked.",
				"properties": {
					"id": {
						"type": "string",
						"format": "uuid"
					},
					"name": {
						"type": "string"
					},
					"webhook_url": {
						"type": "string",
						"nullable": true
					},
					"webhook_secret_masked": {
						"type": "string",
						"nullable": true,
						"description": "Last 4 characters of the webhook secret (e.g. '****cret')"
					},
					"has_webhook_secret": {
						"type": "boolean",
						"description": "Whether a webhook secret is configured"
					},
					"notify_confirmation_updates": {
						"type": "boolean",
						"description": "Whether opt-in transaction.confirmation_update webhooks are enabled (default false)"
					},
					"min_confirmations": {
						"type": "integer",
						"nullable": true
					},
					"sweep_wallet_evm": {
						"type": "string",
						"nullable": true,
						"description": "EVM destination wallet (0x...) used by EVM sweep cron"
					},
					"sweep_wallet_tron": {
						"type": "string",
						"nullable": true,
						"description": "TRON destination wallet (T...) used by TRON sweep cron"
					},
					"payout_method": {
						"type": "string",
						"enum": [
							"wallet",
							"qvapay",
							"zelle"
						],
						"nullable": true
					},
					"qvapay_account": {
						"type": "string",
						"nullable": true
					},
					"zelle_contact": {
						"type": "string",
						"nullable": true
					},
					"created_at": {
						"type": "string",
						"format": "date-time"
					}
				}
			},
			"UpdateConfigRequest": {
				"type": "object",
				"description": "Include only the fields you want to update. All fields are optional.",
				"properties": {
					"webhook_url": {
						"type": "string",
						"format": "uri",
						"nullable": true,
						"description": "HTTPS URL for webhook notifications. Set to null to remove."
					},
					"webhook_secret": {
						"type": "string",
						"nullable": true,
						"maxLength": 256,
						"description": "Secret for HMAC-SHA256 signing. Set to null to remove."
					},
					"notify_confirmation_updates": {
						"type": "boolean",
						"description": "Enable/disable opt-in transaction.confirmation_update webhooks (confirmation-progress events on EVM + BTC/LTC). Default false."
					},
					"payout_method": {
						"type": "string",
						"enum": [
							"wallet",
							"qvapay",
							"zelle"
						],
						"nullable": true,
						"description": "Payout method. Set to null to clear. Changing this clears the previous method's fields."
					},
					"sweep_wallet_evm": {
						"type": "string",
						"nullable": true,
						"description": "EVM address (0x...) for crypto payouts on EVM chains. Set to null to clear."
					},
					"sweep_wallet_tron": {
						"type": "string",
						"nullable": true,
						"description": "TRON Base58 address (T...) for crypto payouts on TRON. Set to null to clear."
					},
					"sweep_wallet": {
						"type": "string",
						"nullable": true,
						"deprecated": true,
						"description": "DEPRECATED — alias of sweep_wallet_evm kept for backwards compatibility."
					},
					"qvapay_account": {
						"type": "string",
						"nullable": true,
						"minLength": 2,
						"maxLength": 100,
						"description": "QvaPay account (required when switching to qvapay)"
					},
					"zelle_contact": {
						"type": "string",
						"nullable": true,
						"minLength": 2,
						"maxLength": 100,
						"description": "Zelle contact (required when switching to zelle)"
					},
					"min_confirmations": {
						"type": "integer",
						"minimum": 1,
						"maximum": 100,
						"description": "Block confirmations required before confirming a transaction"
					}
				}
			},
			"AssignRequest": {
				"type": "object",
				"properties": {
					"label": {
						"type": "string",
						"description": "Optional label for the wallet (e.g. user ID, order ID). Reusing a label returns the existing *active* wallet for the same client; deactivated wallets are never reused.",
						"example": "user-deposit-42"
					},
					"single_use": {
						"type": "boolean",
						"default": false,
						"description": "If true, the wallet is automatically marked `inactive` after the first successful sweep, removing it from the active scan set. Intended for per-order or per-invoice flows."
					}
				}
			},
			"AssignedWallet": {
				"type": "object",
				"properties": {
					"id": {
						"type": "string",
						"format": "uuid"
					},
					"address": {
						"type": "string",
						"description": "EVM wallet address",
						"example": "0xAbC1234567890DEF1234567890abcdef12345678"
					},
					"label": {
						"type": "string",
						"nullable": true
					},
					"status": {
						"type": "string",
						"enum": [
							"active",
							"inactive"
						],
						"example": "active"
					},
					"single_use": {
						"type": "boolean",
						"description": "Echoes the value passed at assignment. When true, the wallet is auto-deactivated after the first successful sweep."
					},
					"created_at": {
						"type": "string",
						"format": "date-time"
					}
				}
			},
			"AddressRequest": {
				"type": "object",
				"required": [
					"address"
				],
				"properties": {
					"address": {
						"type": "string",
						"description": "EVM wallet address to query"
					}
				}
			},
			"WalletInfo": {
				"type": "object",
				"properties": {
					"address": {
						"type": "string"
					},
					"label": {
						"type": "string",
						"nullable": true
					},
					"status": {
						"type": "string",
						"enum": [
							"active",
							"inactive"
						]
					}
				}
			},
			"Balances": {
				"type": "object",
				"properties": {
					"NativeToken": {
						"type": "string",
						"description": "Native token balance (BNB, ETH, POL, etc.)",
						"example": "0.0042"
					},
					"USDT": {
						"type": "string",
						"description": "USDT balance",
						"example": "150.50"
					},
					"USDC": {
						"type": "string",
						"description": "USDC balance",
						"example": "75.00"
					}
				}
			},
			"TransactionsRequest": {
				"type": "object",
				"required": [
					"address"
				],
				"properties": {
					"address": {
						"type": "string",
						"description": "EVM wallet address"
					},
					"limit": {
						"type": "integer",
						"minimum": 1,
						"maximum": 100,
						"default": 50,
						"description": "Max results per page"
					},
					"offset": {
						"type": "integer",
						"minimum": 0,
						"default": 0,
						"description": "Number of records to skip"
					},
					"status": {
						"type": "string",
						"enum": [
							"detected",
							"confirmed",
							"notified",
							"swept"
						],
						"description": "Filter by transaction status"
					},
					"asset": {
						"type": "string",
						"enum": [
							"USDT",
							"USDC",
							"BNB",
							"ETH",
							"POL"
						],
						"description": "Filter by asset. Native assets (BNB/ETH/POL) only exist on their own network (bsc/eth/pol)."
					}
				}
			},
			"Transaction": {
				"type": "object",
				"properties": {
					"tx_hash": {
						"type": "string",
						"example": "0xabc123..."
					},
					"log_index": {
						"type": "integer"
					},
					"block_number": {
						"type": "integer"
					},
					"from_address": {
						"type": "string"
					},
					"to_address": {
						"type": "string"
					},
					"asset": {
						"type": "string",
						"enum": [
							"USDT",
							"USDC",
							"BNB",
							"ETH",
							"POL"
						],
						"description": "Deposited asset. Native coins are deposit assets on bsc (BNB), eth (ETH) and pol (POL) only — not on arb/base/opt/avax."
					},
					"amount": {
						"type": "string",
						"example": "100.00"
					},
					"price_usd_at_detect": {
						"type": "number",
						"nullable": true,
						"description": "USD spot price snapshot taken when the deposit was detected. Populated for native assets (BNB/ETH/POL); null for stablecoins."
					},
					"confirmations": {
						"type": "integer"
					},
					"status": {
						"type": "string",
						"enum": [
							"detected",
							"confirmed",
							"notified",
							"swept"
						]
					},
					"detected_at": {
						"type": "string",
						"format": "date-time"
					},
					"created_at": {
						"type": "string",
						"format": "date-time"
					}
				}
			},
			"AssignedTronWallet": {
				"type": "object",
				"properties": {
					"id": {
						"type": "string",
						"format": "uuid"
					},
					"address": {
						"type": "string",
						"description": "TRON wallet address (Base58, starts with T).",
						"example": "TCsHYKC27np7cGAxJEq55DnsGysejpFF11"
					},
					"label": {
						"type": "string",
						"nullable": true
					},
					"status": {
						"type": "string",
						"enum": [
							"active",
							"inactive"
						],
						"example": "active"
					},
					"activated": {
						"type": "boolean",
						"description": "Whether the TRON account is activated on-chain. New wallets start as `false` and are lazily activated on first sweep."
					},
					"single_use": {
						"type": "boolean",
						"description": "Echoes the value passed at assignment. When true, the wallet is auto-deactivated after the first successful sweep."
					},
					"created_at": {
						"type": "string",
						"format": "date-time"
					}
				}
			},
			"TronAddressRequest": {
				"type": "object",
				"required": [
					"address"
				],
				"properties": {
					"address": {
						"type": "string",
						"description": "TRON Base58 wallet address to query",
						"example": "TCsHYKC27np7cGAxJEq55DnsGysejpFF11"
					}
				}
			},
			"TronBalances": {
				"type": "object",
				"description": "TRON balances reported as both raw integer (smallest unit) and human-readable formatted string.",
				"properties": {
					"TRX": {
						"$ref": "#/components/schemas/TronBalanceEntry"
					},
					"USDT": {
						"$ref": "#/components/schemas/TronBalanceEntry"
					}
				}
			},
			"TronBalanceEntry": {
				"type": "object",
				"properties": {
					"raw": {
						"type": "string",
						"description": "Raw on-chain integer in smallest unit (TRX uses 6-decimal SUN, USDT TRC20 uses 6 decimals).",
						"example": "1500000"
					},
					"formatted": {
						"type": "string",
						"description": "Human-readable amount.",
						"example": "1.5"
					}
				}
			},
			"TronTransactionsRequest": {
				"type": "object",
				"properties": {
					"address": {
						"type": "string",
						"description": "Optional TRON Base58 wallet address. If omitted, returns transactions across all of the client's TRON wallets.",
						"example": "TCsHYKC27np7cGAxJEq55DnsGysejpFF11"
					},
					"limit": {
						"type": "integer",
						"minimum": 1,
						"maximum": 200,
						"default": 50,
						"description": "Max results per page (capped server-side at 200)."
					},
					"offset": {
						"type": "integer",
						"minimum": 0,
						"default": 0,
						"description": "Number of records to skip. The response does not include a total count — request `limit + 1` results to detect more pages."
					},
					"status": {
						"type": "string",
						"enum": [
							"detected",
							"confirmed",
							"notified",
							"swept"
						],
						"description": "Filter by transaction status."
					},
					"asset": {
						"type": "string",
						"enum": [
							"USDT",
							"TRX"
						],
						"description": "Filter by asset."
					}
				}
			},
			"TronTransaction": {
				"type": "object",
				"properties": {
					"id": {
						"type": "string",
						"format": "uuid"
					},
					"tx_id": {
						"type": "string",
						"description": "TRON transaction id (hex, no 0x prefix).",
						"example": "abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789"
					},
					"event_index": {
						"type": "integer",
						"description": "Index of the Transfer event within the transaction (a single tx can contain multiple deposits)."
					},
					"block_number": {
						"type": "integer"
					},
					"block_timestamp": {
						"type": "integer",
						"description": "Block timestamp in milliseconds since epoch."
					},
					"from_address": {
						"type": "string"
					},
					"to_address": {
						"type": "string"
					},
					"asset": {
						"type": "string",
						"enum": [
							"USDT",
							"TRX"
						],
						"description": "V2 TRON accepts USDT (TRC20) and native TRX. Only direct TRX transfers are detected — TRX moved inside a contract call (internal transactions) is not."
					},
					"amount": {
						"type": "string",
						"example": "100.00"
					},
					"amount_raw": {
						"type": "string",
						"description": "Raw amount in smallest unit (USDT TRC20 uses 6 decimals; TRX uses 6-decimal SUN).",
						"example": "100000000"
					},
					"price_usd_at_detect": {
						"type": "number",
						"nullable": true,
						"description": "TRX/USD spot price snapshot taken when the deposit was detected. Populated for TRX deposits; null for USDT."
					},
					"confirmations": {
						"type": "integer"
					},
					"status": {
						"type": "string",
						"enum": [
							"detected",
							"confirmed",
							"notified",
							"swept"
						]
					},
					"webhook_sent": {
						"type": "boolean"
					},
					"detected_at": {
						"type": "string",
						"format": "date-time"
					},
					"updated_at": {
						"type": "string",
						"format": "date-time"
					},
					"wallet_id": {
						"type": "string",
						"format": "uuid"
					}
				}
			},
			"AssignedSolWallet": {
				"type": "object",
				"properties": {
					"id": {
						"type": "string",
						"format": "uuid"
					},
					"address": {
						"type": "string",
						"description": "Solana wallet address (Base58 Ed25519 pubkey, ~44 chars).",
						"example": "5kQwVxYzABc1d2eF3gH4iJ5kL6mN7oP8qR9sTuVwXyZ1"
					},
					"label": {
						"type": "string",
						"nullable": true
					},
					"status": {
						"type": "string",
						"enum": [
							"active",
							"inactive"
						],
						"example": "active"
					},
					"single_use": {
						"type": "boolean",
						"description": "Echoes the value passed at assignment. When true, the wallet is auto-deactivated after the first successful sweep."
					},
					"created_at": {
						"type": "string",
						"format": "date-time"
					}
				}
			},
			"SolAddressRequest": {
				"type": "object",
				"required": [
					"address"
				],
				"properties": {
					"address": {
						"type": "string",
						"description": "Solana Base58 wallet address (Ed25519 pubkey).",
						"example": "5kQwVxYzABc1d2eF3gH4iJ5kL6mN7oP8qR9sTuVwXyZ1"
					}
				}
			},
			"SolBalances": {
				"type": "object",
				"description": "Solana balances reported as both raw integer (smallest unit) and human-readable formatted string.",
				"properties": {
					"SOL": {
						"$ref": "#/components/schemas/SolBalanceEntry"
					},
					"USDT": {
						"$ref": "#/components/schemas/SolBalanceEntry"
					},
					"USDC": {
						"$ref": "#/components/schemas/SolBalanceEntry"
					}
				}
			},
			"SolBalanceEntry": {
				"type": "object",
				"properties": {
					"raw": {
						"type": "string",
						"description": "Raw on-chain integer in smallest unit (SOL uses 9 decimals — lamports; USDT-SPL, USDC-SPL and USDG-SPL use 6 decimals). Reported as 0 when the ATA does not exist yet.",
						"example": "500000"
					},
					"formatted": {
						"type": "string",
						"description": "Human-readable amount.",
						"example": "0.5"
					}
				}
			},
			"SolTransactionsRequest": {
				"type": "object",
				"properties": {
					"address": {
						"type": "string",
						"description": "Optional Solana Base58 wallet address. If omitted, returns transactions across all of the client's Solana wallets.",
						"example": "5kQwVxYzABc1d2eF3gH4iJ5kL6mN7oP8qR9sTuVwXyZ1"
					},
					"limit": {
						"type": "integer",
						"minimum": 1,
						"maximum": 200,
						"default": 50,
						"description": "Max results per page (capped server-side at 200)."
					},
					"offset": {
						"type": "integer",
						"minimum": 0,
						"default": 0,
						"description": "Number of records to skip. The response does not include a total count — request `limit + 1` results to detect more pages."
					},
					"status": {
						"type": "string",
						"enum": [
							"detected",
							"confirmed",
							"notified",
							"swept"
						],
						"description": "Filter by transaction status."
					},
					"asset": {
						"type": "string",
						"enum": [
							"USDT",
							"USDC",
							"USDG",
							"SOL"
						],
						"description": "Filter by asset."
					}
				}
			},
			"SolTransaction": {
				"type": "object",
				"properties": {
					"id": {
						"type": "string",
						"format": "uuid"
					},
					"tx_signature": {
						"type": "string",
						"description": "Solana transaction signature (Base58, 87-88 chars).",
						"example": "3jK9pQrSt7uVxYz1A2bC3dE4fG5hI6jK7lM8nO9pQ1rS2tU3vW4xY5zA6bC7dE8fG9hI"
					},
					"instruction_index": {
						"type": "integer",
						"description": "Account index within the tx that received the deposit (`accountIndex` from `meta.postTokenBalances`). Stable within a tx — used together with `tx_signature` for uniqueness when a single atomic tx credits multiple of our wallets."
					},
					"slot": {
						"type": "integer",
						"description": "Solana slot where the transaction was finalized."
					},
					"block_time": {
						"type": "string",
						"format": "date-time",
						"nullable": true
					},
					"from_address": {
						"type": "string",
						"nullable": true,
						"description": "Best-effort sender attribution from `meta.preTokenBalances`. Solana doesn't bind source 1:1 on multi-leg txs, so this is an indicator only."
					},
					"to_address": {
						"type": "string",
						"description": "Recipient owner address (your assigned wallet)."
					},
					"asset": {
						"type": "string",
						"enum": [
							"USDT",
							"USDC",
							"USDG",
							"SOL"
						],
						"description": "V2 SOL accepts USDT-SPL, USDC-SPL, and native SOL (deposits of at least 0.005 SOL)."
					},
					"amount": {
						"type": "string",
						"example": "100.00"
					},
					"amount_raw": {
						"type": "string",
						"description": "Raw amount in smallest unit (USDT-SPL, USDC-SPL and USDG-SPL use 6 decimals; SOL uses 9-decimal lamports).",
						"example": "100000000"
					},
					"price_usd_at_detect": {
						"type": "number",
						"nullable": true,
						"description": "SOL/USD spot price snapshot taken when the deposit was detected. Populated for SOL deposits; null for stablecoins."
					},
					"confirmations": {
						"type": "integer",
						"description": "0 = detected, 1 = finalized. Solana doesn't accumulate confirmations like EVM — `finalized` commitment is the threshold."
					},
					"status": {
						"type": "string",
						"enum": [
							"detected",
							"confirmed",
							"notified",
							"swept"
						]
					},
					"webhook_sent": {
						"type": "boolean"
					},
					"created_at": {
						"type": "string",
						"format": "date-time"
					},
					"updated_at": {
						"type": "string",
						"format": "date-time"
					},
					"wallet_id": {
						"type": "string",
						"format": "uuid"
					}
				}
			},
			"BtcAddressRequest": {
				"type": "object",
				"required": [
					"address"
				],
				"properties": {
					"address": {
						"type": "string",
						"description": "Bitcoin P2WPKH (bech32) wallet address owned by the authenticated client.",
						"example": "bc1qw4lvtv08phk49cw2ucpvxhc8sy54ja2v9376k2"
					}
				}
			},
			"AssignedBtcWallet": {
				"type": "object",
				"properties": {
					"id": {
						"type": "string",
						"format": "uuid"
					},
					"address": {
						"type": "string",
						"description": "Bitcoin P2WPKH (native SegWit, bech32) deposit address.",
						"example": "bc1qw4lvtv08phk49cw2ucpvxhc8sy54ja2v9376k2"
					},
					"label": {
						"type": "string",
						"nullable": true
					},
					"status": {
						"type": "string",
						"enum": [
							"active",
							"inactive"
						],
						"example": "active"
					},
					"single_use": {
						"type": "boolean",
						"description": "Echoes the value passed at assignment. When true, the wallet is auto-deactivated after the first successful sweep."
					},
					"created_at": {
						"type": "string",
						"format": "date-time"
					}
				}
			},
			"BtcBalances": {
				"type": "object",
				"description": "Native BTC balance split by confirmation state, computed from the tracked UTXO set.",
				"properties": {
					"BTC": {
						"type": "object",
						"properties": {
							"confirmed": {
								"type": "string",
								"description": "Confirmed balance in BTC.",
								"example": "0.00150000"
							},
							"unconfirmed": {
								"type": "string",
								"description": "Unconfirmed (mempool) balance in BTC.",
								"example": "0.00000000"
							},
							"confirmed_sats": {
								"type": "string",
								"description": "Confirmed balance in satoshis, as a string.",
								"example": "150000"
							},
							"unconfirmed_sats": {
								"type": "string",
								"description": "Unconfirmed balance in satoshis, as a string.",
								"example": "0"
							}
						}
					}
				}
			},
			"BtcTransaction": {
				"type": "object",
				"properties": {
					"id": {
						"type": "string",
						"format": "uuid"
					},
					"block_time": {
						"type": "string",
						"format": "date-time",
						"nullable": true
					},
					"from_address": {
						"type": "string",
						"nullable": true
					},
					"to_address": {
						"type": "string"
					},
					"amount": {
						"type": "string",
						"description": "Human-readable decimal amount."
					},
					"amount_raw": {
						"type": "string",
						"description": "Integer amount in the smallest unit, as a string."
					},
					"confirmations": {
						"type": "integer"
					},
					"status": {
						"type": "string",
						"enum": [
							"detected",
							"confirmed",
							"notified",
							"swept"
						]
					},
					"webhook_sent": {
						"type": "boolean"
					},
					"created_at": {
						"type": "string",
						"format": "date-time"
					},
					"updated_at": {
						"type": "string",
						"format": "date-time"
					},
					"wallet_id": {
						"type": "string",
						"format": "uuid"
					},
					"tx_hash": {
						"type": "string",
						"description": "Bitcoin transaction id (hex)."
					},
					"vout_index": {
						"type": "integer",
						"description": "Output index inside the transaction. A BTC deposit is uniquely identified by `(tx_hash, vout_index)` — one tx can fund the same wallet through several outputs."
					},
					"block_number": {
						"type": "integer",
						"nullable": true
					},
					"asset": {
						"type": "string",
						"enum": [
							"BTC"
						]
					},
					"price_usd_at_detect": {
						"type": "number",
						"nullable": true,
						"description": "BTC/USD price snapshot taken when the deposit was detected."
					}
				}
			},
			"BtcTransactionsRequest": {
				"type": "object",
				"properties": {
					"address": {
						"type": "string",
						"description": "Optional bech32 wallet address. If omitted, returns transactions across all of the client's BTC wallets.",
						"example": "bc1qw4lvtv08phk49cw2ucpvxhc8sy54ja2v9376k2"
					},
					"limit": {
						"type": "integer",
						"minimum": 1,
						"maximum": 200,
						"default": 50
					},
					"offset": {
						"type": "integer",
						"minimum": 0,
						"default": 0
					},
					"status": {
						"type": "string",
						"enum": [
							"detected",
							"confirmed",
							"notified",
							"swept"
						]
					}
				}
			},
			"LtcAddressRequest": {
				"type": "object",
				"required": [
					"address"
				],
				"properties": {
					"address": {
						"type": "string",
						"description": "Litecoin P2WPKH (bech32) wallet address owned by the authenticated client.",
						"example": "ltc1qtxu9nztx0cmm8kfz4fdwvya4pn9m2sf29ekvpul"
					}
				}
			},
			"AssignedLtcWallet": {
				"type": "object",
				"properties": {
					"id": {
						"type": "string",
						"format": "uuid"
					},
					"address": {
						"type": "string",
						"description": "Litecoin P2WPKH (native SegWit, bech32) deposit address.",
						"example": "ltc1qtxu9nztx0cmm8kfz4fdwvya4pn9m2sf29ekvpul"
					},
					"label": {
						"type": "string",
						"nullable": true
					},
					"status": {
						"type": "string",
						"enum": [
							"active",
							"inactive"
						],
						"example": "active"
					},
					"single_use": {
						"type": "boolean",
						"description": "Echoes the value passed at assignment. When true, the wallet is auto-deactivated after the first successful sweep."
					},
					"created_at": {
						"type": "string",
						"format": "date-time"
					}
				}
			},
			"LtcBalances": {
				"type": "object",
				"description": "Native LTC balance split by confirmation state, computed from the tracked UTXO set. The `*_sats` fields are litoshis (1 litoshi = 1e-8 LTC).",
				"properties": {
					"LTC": {
						"type": "object",
						"properties": {
							"confirmed": {
								"type": "string",
								"description": "Confirmed balance in LTC.",
								"example": "0.25000000"
							},
							"unconfirmed": {
								"type": "string",
								"description": "Unconfirmed (mempool) balance in LTC.",
								"example": "0.00000000"
							},
							"confirmed_sats": {
								"type": "string",
								"description": "Confirmed balance in litoshis (1e-8 LTC), as a string.",
								"example": "25000000"
							},
							"unconfirmed_sats": {
								"type": "string",
								"description": "Unconfirmed balance in litoshis (1e-8 LTC), as a string.",
								"example": "0"
							}
						}
					}
				}
			},
			"LtcTransaction": {
				"type": "object",
				"properties": {
					"id": {
						"type": "string",
						"format": "uuid"
					},
					"block_time": {
						"type": "string",
						"format": "date-time",
						"nullable": true
					},
					"from_address": {
						"type": "string",
						"nullable": true
					},
					"to_address": {
						"type": "string"
					},
					"amount": {
						"type": "string",
						"description": "Human-readable decimal amount."
					},
					"amount_raw": {
						"type": "string",
						"description": "Integer amount in litoshis (1e-8 LTC), as a string."
					},
					"confirmations": {
						"type": "integer"
					},
					"status": {
						"type": "string",
						"enum": [
							"detected",
							"confirmed",
							"notified",
							"swept"
						]
					},
					"webhook_sent": {
						"type": "boolean"
					},
					"created_at": {
						"type": "string",
						"format": "date-time"
					},
					"updated_at": {
						"type": "string",
						"format": "date-time"
					},
					"wallet_id": {
						"type": "string",
						"format": "uuid"
					},
					"tx_hash": {
						"type": "string",
						"description": "Litecoin transaction id (hex)."
					},
					"vout_index": {
						"type": "integer",
						"description": "Output index inside the transaction. An LTC deposit is uniquely identified by `(tx_hash, vout_index)` — one tx can fund the same wallet through several outputs."
					},
					"block_number": {
						"type": "integer",
						"nullable": true
					},
					"asset": {
						"type": "string",
						"enum": [
							"LTC"
						]
					},
					"price_usd_at_detect": {
						"type": "number",
						"nullable": true,
						"description": "LTC/USD price snapshot taken when the deposit was detected."
					}
				}
			},
			"LtcTransactionsRequest": {
				"type": "object",
				"properties": {
					"address": {
						"type": "string",
						"description": "Optional bech32 wallet address. If omitted, returns transactions across all of the client's LTC wallets.",
						"example": "ltc1qtxu9nztx0cmm8kfz4fdwvya4pn9m2sf29ekvpul"
					},
					"limit": {
						"type": "integer",
						"minimum": 1,
						"maximum": 200,
						"default": 50
					},
					"offset": {
						"type": "integer",
						"minimum": 0,
						"default": 0
					},
					"status": {
						"type": "string",
						"enum": [
							"detected",
							"confirmed",
							"notified",
							"swept"
						]
					}
				}
			},
			"TonAddressRequest": {
				"type": "object",
				"required": [
					"address"
				],
				"properties": {
					"address": {
						"type": "string",
						"description": "TON wallet address owned by the authenticated client. Pass the exact address string returned at assignment.",
						"example": "UQAkEWzRLUUEygDpTzbcDsM6V4Wm65DZTcBgw0sFcj-VHJtu"
					}
				}
			},
			"AssignedTonWallet": {
				"type": "object",
				"properties": {
					"id": {
						"type": "string",
						"format": "uuid"
					},
					"address": {
						"type": "string",
						"description": "TON deposit address (user-friendly base64url form). USDT (Jetton) deposits sent to this address are detected on its derived jetton wallet automatically; native GRAM deposits are detected on the address itself.",
						"example": "UQAkEWzRLUUEygDpTzbcDsM6V4Wm65DZTcBgw0sFcj-VHJtu"
					},
					"label": {
						"type": "string",
						"nullable": true
					},
					"status": {
						"type": "string",
						"enum": [
							"active",
							"inactive"
						],
						"example": "active"
					},
					"single_use": {
						"type": "boolean",
						"description": "Echoes the value passed at assignment. When true, the wallet is auto-deactivated after the first successful sweep."
					},
					"created_at": {
						"type": "string",
						"format": "date-time"
					}
				}
			},
			"TonBalanceEntry": {
				"type": "object",
				"properties": {
					"raw": {
						"type": "string",
						"description": "Integer balance in the smallest unit (nanograms for GRAM, 6-decimal raw for USDT), as a string."
					},
					"formatted": {
						"type": "string",
						"description": "Human-readable decimal string."
					}
				}
			},
			"TonBalances": {
				"type": "object",
				"properties": {
					"GRAM": {
						"$ref": "#/components/schemas/TonBalanceEntry"
					},
					"TON": {
						"allOf": [
							{
								"$ref": "#/components/schemas/TonBalanceEntry"
							}
						],
						"deprecated": true,
						"description": "Deprecated alias of GRAM (pre-rebrand native ticker), kept for backward compatibility."
					},
					"USDT": {
						"$ref": "#/components/schemas/TonBalanceEntry"
					}
				}
			},
			"TonTransaction": {
				"type": "object",
				"properties": {
					"id": {
						"type": "string",
						"format": "uuid"
					},
					"block_time": {
						"type": "string",
						"format": "date-time",
						"nullable": true
					},
					"from_address": {
						"type": "string",
						"nullable": true
					},
					"to_address": {
						"type": "string"
					},
					"amount": {
						"type": "string",
						"description": "Human-readable decimal amount."
					},
					"amount_raw": {
						"type": "string",
						"description": "Integer amount in the smallest unit, as a string."
					},
					"confirmations": {
						"type": "integer"
					},
					"status": {
						"type": "string",
						"enum": [
							"detected",
							"confirmed",
							"notified",
							"swept"
						]
					},
					"webhook_sent": {
						"type": "boolean"
					},
					"created_at": {
						"type": "string",
						"format": "date-time"
					},
					"updated_at": {
						"type": "string",
						"format": "date-time"
					},
					"wallet_id": {
						"type": "string",
						"format": "uuid"
					},
					"tx_hash": {
						"type": "string",
						"description": "Hex hash of the inbound transfer transaction on TON (on the derived jetton wallet for USDT, on the wallet address itself for GRAM)."
					},
					"lt": {
						"type": "string",
						"description": "Account logical time of the transaction. A TON deposit is uniquely identified by `(tx_hash, lt)`."
					},
					"asset": {
						"type": "string",
						"enum": [
							"USDT",
							"GRAM"
						]
					}
				}
			},
			"TonTransactionsRequest": {
				"type": "object",
				"properties": {
					"address": {
						"type": "string",
						"description": "Optional TON wallet address (exact string returned at assignment). If omitted, returns transactions across all of the client's TON wallets.",
						"example": "UQAkEWzRLUUEygDpTzbcDsM6V4Wm65DZTcBgw0sFcj-VHJtu"
					},
					"limit": {
						"type": "integer",
						"minimum": 1,
						"maximum": 200,
						"default": 50
					},
					"offset": {
						"type": "integer",
						"minimum": 0,
						"default": 0
					},
					"status": {
						"type": "string",
						"enum": [
							"detected",
							"confirmed",
							"notified",
							"swept"
						]
					}
				}
			},
			"WebhookPayload": {
				"type": "object",
				"description": "Webhook payload sent to your configured URL for deposit events (transaction.incoming, transaction.confirmation_update, transaction.confirmed). The transaction.swept event uses a different data shape — see WebhookSweptPayload.",
				"required": [
					"event",
					"timestamp",
					"data"
				],
				"properties": {
					"event": {
						"type": "string",
						"enum": [
							"transaction.incoming",
							"transaction.confirmation_update",
							"transaction.confirmed"
						],
						"description": "`transaction.incoming` — deposit detected but not yet confirmed. `transaction.confirmation_update` — confirmation count advanced while still pending (opt-in via `notify_confirmation_updates`, EVM + BTC/LTC only; fire-and-forget, no retries, ordering vs transaction.confirmed not guaranteed — cosmetic only, never credit funds from it). `transaction.confirmed` — deposit has reached minimum confirmations."
					},
					"timestamp": {
						"type": "string",
						"format": "date-time",
						"description": "ISO 8601 timestamp of when the notification was generated."
					},
					"data": {
						"$ref": "#/components/schemas/WebhookTransactionData"
					}
				}
			},
			"WebhookSweptPayload": {
				"type": "object",
				"description": "Webhook payload sent best-effort after funds have been swept on-chain to the configured destination.",
				"required": [
					"event",
					"timestamp",
					"data"
				],
				"properties": {
					"event": {
						"type": "string",
						"enum": [
							"transaction.swept"
						]
					},
					"timestamp": {
						"type": "string",
						"format": "date-time"
					},
					"data": {
						"$ref": "#/components/schemas/WebhookSweptData"
					}
				}
			},
			"WebhookSweptData": {
				"type": "object",
				"description": "Sweep details included in transaction.swept notifications. Same amount contract as WebhookTransactionData: `amount`/`gross_amount`/`fee_amount` are USD-equivalent; `*_native` and `price_usd` carry the on-chain unit and spot.",
				"properties": {
					"sweep_tx_hash": {
						"type": "string",
						"nullable": true,
						"description": "On-chain hash of the sweep transaction. May be null if the asset was below dust threshold and only the fee leg was emitted."
					},
					"fee_tx_hash": {
						"type": "string",
						"nullable": true,
						"description": "On-chain hash of the fee transaction (only present when payout_method='wallet' and a fee was applied). For BTC/LTC, this equals `sweep_tx_hash` because the fee is a vout of the same atomic tx. On other chains it may also equal `sweep_tx_hash` when the fee wallet and the payout destination are the same address — the fee is then collected inside the single sweep transaction instead of a separate transfer."
					},
					"funding_tx_hash": {
						"type": "string",
						"nullable": true,
						"description": "On-chain hash of the gas-funding transaction sent from the platform main wallet (EVM only — when the wallet did not have enough native to pay gas). Not used for TRON (uses energy/bandwidth delegation), SOL (uses fee-payer delegation in the atomic sweep tx), or BTC/LTC (each wallet pays its own miner fee from its UTXOs)."
					},
					"source_tx_hashes": {
						"type": "array",
						"items": {
							"type": "string"
						},
						"description": "Hashes of the original incoming deposit transactions consolidated by this sweep. For BTC/LTC, entries are formatted `<tx_hash>:<vout_index>` to uniquely identify each consumed UTXO."
					},
					"asset": {
						"type": "string",
						"enum": [
							"USDT",
							"USDC",
							"BTC",
							"LTC",
							"TRX",
							"SOL",
							"BNB",
							"ETH",
							"POL"
						]
					},
					"amount": {
						"type": "string",
						"description": "Net USD-equivalent amount delivered to the destination (after fee, when applicable). For stablecoins matches `amount_native` 1:1; for native assets (BTC/LTC/TRX/SOL/BNB/ETH/POL) = `amount_native × price_usd`."
					},
					"amount_native": {
						"type": "string",
						"description": "Net on-chain amount in the asset's native unit. Equals `amount` for stablecoins."
					},
					"gross_amount": {
						"type": "string",
						"description": "Gross USD-equivalent amount before fee deduction."
					},
					"gross_amount_native": {
						"type": "string",
						"description": "Gross on-chain amount in the asset's native unit."
					},
					"fee_amount": {
						"type": "string",
						"nullable": true,
						"description": "Wallet sweep fee in USD-equivalent (null when no fee applied)."
					},
					"fee_amount_native": {
						"type": "string",
						"nullable": true,
						"description": "Wallet sweep fee in the asset's native unit (null when no fee applied)."
					},
					"price_usd": {
						"type": "number",
						"description": "USD spot used for the conversion. `1.00` for stablecoins; for native assets (BTC/LTC/TRX/SOL/BNB/ETH/POL) the spot at sweep time (which may differ slightly from the detect-time price stored on the source transactions)."
					},
					"destination": {
						"type": "string",
						"description": "Address that received the swept funds. For payout_method='wallet' this is the client's sweep_wallet_evm/_tron/_sol/_btc/_ltc depending on network; otherwise the platform main wallet."
					},
					"wallet_address": {
						"type": "string",
						"description": "Address of the deposit wallet the funds were swept from."
					},
					"wallet_label": {
						"type": "string",
						"nullable": true
					},
					"network": {
						"type": "string",
						"enum": [
							"bsc",
							"eth",
							"pol",
							"arb",
							"base",
							"avax",
							"rh",
							"tron",
							"solana",
							"btc",
							"ltc",
							"ton",
							"xlm"
						]
					},
					"wallet_memo": {
						"type": "string",
						"description": "XLM only: memo id of the swept wallet. XLM sweeps are batched per client and asset, so one Stellar tx can cover several memo wallets; one transaction.swept is sent per wallet with its share of the fee."
					},
					"in_place": {
						"type": "boolean",
						"description": "XLM only: true when the custody destination is the deposit account itself, so nothing moved on chain (`sweep_tx_hash` is null)."
					}
				}
			},
			"WebhookTransactionData": {
				"type": "object",
				"description": "Transaction details included in webhook notifications. The `amount` field is always the USD-equivalent value; `amount_native` and `price_usd` provide the on-chain unit and spot used for the conversion (price_usd is 1.00 for stablecoins, fetched from CoinGecko and frozen at detect time for native assets — BTC, LTC, TRX, SOL, BNB, ETH, POL). If no USD price is available, the notification is deferred to the next cron tick rather than sent with partial data.",
				"properties": {
					"tx_hash": {
						"type": "string",
						"description": "On-chain transaction hash. For BTC/LTC, identify a deposit uniquely with the combination `(tx_hash, vout_index)`.",
						"example": "0xabc123def456789abc123def456789abc123def456789abc123def456789abcd"
					},
					"vout_index": {
						"type": "integer",
						"nullable": true,
						"description": "BTC/LTC only: the output index within the transaction that credited the wallet (a single UTXO-chain tx can credit a wallet across multiple vouts). Null for non-UTXO chains.",
						"example": 0
					},
					"block_number": {
						"type": "integer",
						"description": "Block number where the transaction was included. For SOL this is the `slot`.",
						"example": 48123456
					},
					"ledger": {
						"type": "integer",
						"description": "XLM only: ledger sequence the payment closed in.",
						"example": 64820889
					},
					"memo": {
						"type": "string",
						"description": "XLM only: memo id of the credited wallet (decimal string). All XLM wallets share `to_address`; the memo is what identifies the wallet.",
						"example": "1234567890123456789"
					},
					"from_address": {
						"type": "string",
						"nullable": true,
						"description": "Sender address. Always populated on EVM/TRON/SOL. For BTC/LTC this is null by design — UTXO model has no single canonical sender (txs can have multiple inputs from different addresses).",
						"example": "0x742d35Cc6634C0532925a3b844Bc9e7595f2bD18"
					},
					"to_address": {
						"type": "string",
						"description": "Recipient address (your assigned wallet).",
						"example": "0xAbC1234567890DEF1234567890abcdef12345678"
					},
					"asset": {
						"type": "string",
						"enum": [
							"USDT",
							"USDC",
							"PYUSD",
							"USDG",
							"ARB",
							"BTC",
							"LTC",
							"TRX",
							"SOL",
							"BNB",
							"ETH",
							"POL",
							"GRAM"
						],
						"description": "Asset deposited. Stablecoins (USDT/USDC/PYUSD/USDG) have 1:1 USD parity; native assets (BTC/LTC/TRX/SOL/BNB/ETH/POL/GRAM) and the ARB token (Arbitrum ERC-20) are converted to USD via the price spot frozen at detect time."
					},
					"amount": {
						"type": "string",
						"description": "USD-equivalent deposit value at event time, formatted as a decimal string (e.g. \"150.50\"). For stablecoins this matches `amount_native` exactly. For native assets (BTC/LTC/TRX/SOL/BNB/ETH/POL/GRAM) and ARB, this is `amount_native × price_usd` rounded to 2 decimals — compare it directly against your order total.",
						"example": "150.50"
					},
					"amount_native": {
						"type": "string",
						"description": "On-chain amount in the asset's native unit, formatted as a decimal string. For stablecoins this equals `amount`. For native assets it's in the coin's own unit — e.g. BTC \"0.00052000\" (52,000 sats), LTC \"0.25000000\" (25,000,000 litoshis), TRX \"120.500000\", SOL \"0.250000000\".",
						"example": "150.50"
					},
					"price_usd": {
						"type": "number",
						"description": "USD spot price of one unit of the native asset at event time. `1.00` for stablecoins. For native assets (BTC/LTC/TRX/SOL/BNB/ETH/POL), the price snapshot frozen at detect time (CoinGecko by default; live fallback if no snapshot). Verify: `amount ≈ amount_native × price_usd`.",
						"example": 1
					},
					"confirmations": {
						"type": "integer",
						"description": "Number of block confirmations at the time of notification. For `transaction.incoming` this may be low (< min_confirmations). For `transaction.confirmed` this will be >= min_confirmations (default 15 for EVM, 19 for TRON, 1 for SOL, 2 for BTC, 6 for LTC).",
						"example": 15
					},
					"min_confirmations": {
						"type": "integer",
						"description": "Target confirmation count for this deposit (client `min_confirmations` override or the chain default). Present only on `transaction.confirmation_update` events — render progress as `confirmations / min_confirmations`.",
						"example": 10
					},
					"wallet_label": {
						"type": "string",
						"nullable": true,
						"description": "The label you assigned to this wallet via the assign endpoint.",
						"example": "user-deposit-42"
					},
					"network": {
						"type": "string",
						"enum": [
							"bsc",
							"eth",
							"pol",
							"arb",
							"base",
							"avax",
							"rh",
							"tron",
							"solana",
							"btc",
							"ltc",
							"ton",
							"xlm"
						],
						"description": "Blockchain network where the transaction occurred. EVM networks emit USDT/USDC (plus PYUSD on eth, the ARB token on arb, USDG on rh, native BNB on bsc, ETH on eth, POL on pol); TRON emits USDT and native TRX; Solana emits USDT-SPL, USDC-SPL, USDG-SPL and native SOL; BTC emits BTC native; LTC emits LTC native. Native ETH on arb/base/opt and native AVAX are not deposit assets.",
						"example": "bsc"
					}
				}
			},
			"ErrorResponse": {
				"type": "object",
				"properties": {
					"error": {
						"type": "string"
					}
				}
			},
			"NetworkInfo": {
				"type": "object",
				"properties": {
					"key": {
						"type": "string",
						"description": "Stable identifier (`tron`, `bsc`, `eth`, `pol`, `arb`, `base`, `opt`, `avax`, `sol`).",
						"example": "bsc"
					},
					"family": {
						"type": "string",
						"enum": [
							"evm",
							"tron",
							"sol"
						],
						"description": "Routing family. Determines which assign / balance / transactions endpoint to use."
					},
					"label": {
						"type": "string",
						"description": "Human-readable network name.",
						"example": "BSC"
					},
					"network_param": {
						"type": "string",
						"nullable": true,
						"description": "Value to send as `network` in EVM endpoint bodies. Null for TRON and Solana (each has its own endpoint family)."
					},
					"native_token": {
						"type": "string",
						"nullable": true,
						"description": "Native token symbol. Present for EVM only.",
						"example": "BNB"
					},
					"default_min_confirmations": {
						"type": "integer",
						"description": "Default `min_confirmations` used by the scan/notify pipeline when the client has not overridden it.",
						"example": 15
					},
					"assets": {
						"type": "array",
						"items": {
							"$ref": "#/components/schemas/NetworkAsset"
						}
					}
				}
			},
			"NetworkAsset": {
				"type": "object",
				"properties": {
					"symbol": {
						"type": "string",
						"example": "USDT"
					},
					"decimals": {
						"type": "integer",
						"example": 6
					},
					"contract": {
						"type": "string",
						"nullable": true,
						"description": "ERC20 contract address. Present for EVM assets; omitted for TRON USDT and Solana SPL tokens (the contract / mint is implicit per family)."
					}
				}
			},
			"EvmBalanceRequest": {
				"type": "object",
				"required": [
					"address"
				],
				"properties": {
					"address": {
						"type": "string",
						"description": "EVM wallet address to query"
					},
					"network": {
						"type": "string",
						"enum": [
							"bsc",
							"eth",
							"pol",
							"arb",
							"base",
							"avax"
						],
						"default": "eth",
						"description": "Chain to read. Each request reads exactly one chain; omitted means `eth`. An unknown value returns 400."
					}
				}
			},
			"EvmCheckHashRequest": {
				"type": "object",
				"required": [
					"network",
					"address",
					"tx_hash"
				],
				"properties": {
					"network": {
						"type": "string",
						"enum": [
							"bsc",
							"eth",
							"pol",
							"arb",
							"base",
							"avax",
							"rh"
						],
						"description": "Chain the transaction was mined on. One EVM wallet row serves every chain, so this selects where to look the hash up."
					},
					"address": {
						"type": "string",
						"description": "One of your EVM deposit addresses (any casing).",
						"example": "0x1234567890abcdef1234567890abcdef12345678"
					},
					"tx_hash": {
						"type": "string",
						"description": "0x-prefixed 64-hex transaction hash.",
						"example": "0x9f2c1d…"
					}
				}
			},
			"TronCheckHashRequest": {
				"type": "object",
				"required": [
					"address",
					"tx_hash"
				],
				"properties": {
					"address": {
						"type": "string",
						"description": "One of your TRON deposit addresses (Base58).",
						"example": "TCsHYKC27np7cGAxJEq55DnsGysejpFF11"
					},
					"tx_hash": {
						"type": "string",
						"description": "64-hex TRON transaction id (0x prefix optional).",
						"example": "6d5e0a…"
					}
				}
			},
			"SolCheckHashRequest": {
				"type": "object",
				"required": [
					"address",
					"tx_hash"
				],
				"properties": {
					"address": {
						"type": "string",
						"description": "One of your Solana deposit addresses (base58).",
						"example": "7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU"
					},
					"tx_hash": {
						"type": "string",
						"description": "Base58 transaction signature.",
						"example": "5UfDq7…"
					}
				}
			},
			"BtcCheckHashRequest": {
				"type": "object",
				"required": [
					"address",
					"tx_hash"
				],
				"properties": {
					"address": {
						"type": "string",
						"description": "One of your Bitcoin deposit addresses (bech32).",
						"example": "bc1q…"
					},
					"tx_hash": {
						"type": "string",
						"description": "64-hex Bitcoin txid.",
						"example": "3a1f9c…"
					}
				}
			},
			"LtcCheckHashRequest": {
				"type": "object",
				"required": [
					"address",
					"tx_hash"
				],
				"properties": {
					"address": {
						"type": "string",
						"description": "One of your Litecoin deposit addresses (bech32).",
						"example": "ltc1q…"
					},
					"tx_hash": {
						"type": "string",
						"description": "64-hex Litecoin txid.",
						"example": "b7c24e…"
					}
				}
			},
			"TonCheckHashRequest": {
				"type": "object",
				"required": [
					"address",
					"tx_hash"
				],
				"properties": {
					"address": {
						"type": "string",
						"description": "One of your TON deposit addresses (any EQ/UQ/raw form).",
						"example": "UQ…"
					},
					"tx_hash": {
						"type": "string",
						"description": "64-hex TON transaction hash (0x prefix optional). For USDT the hash is the one on the wallet's jetton wallet, as shown by explorers under the deposit address.",
						"example": "e4a93b…"
					}
				}
			},
			"CheckHashResponse": {
				"type": "object",
				"properties": {
					"success": {
						"type": "boolean",
						"example": true
					},
					"wallet": {
						"type": "object",
						"properties": {
							"id": {
								"type": "string"
							},
							"address": {
								"type": "string"
							},
							"label": {
								"type": "string",
								"nullable": true
							},
							"status": {
								"type": "string",
								"enum": [
									"active",
									"inactive"
								],
								"description": "Status AFTER the call — `active` when the deposit woke an inactive wallet."
							}
						}
					},
					"tx_hash": {
						"type": "string"
					},
					"network": {
						"type": "string",
						"description": "EVM only."
					},
					"confirmations": {
						"type": "integer",
						"description": "EVM only."
					},
					"credited": {
						"type": "boolean",
						"description": "True when at least one leg of the transaction pays this wallet (whether it was new or already recorded). False means the hash exists but did not pay this address."
					},
					"reactivated": {
						"type": "boolean",
						"description": "True when the wallet was inactive and this call put it back in the scan set. No historical rescan is performed."
					},
					"new_transactions": {
						"type": "integer",
						"description": "Deposit rows inserted by this call (0 on a repeat call — the import is idempotent)."
					},
					"duplicates": {
						"type": "integer",
						"description": "Legs that were already recorded."
					},
					"matches": {
						"type": "array",
						"items": {
							"type": "object",
							"properties": {
								"asset": {
									"type": "string",
									"example": "USDT"
								},
								"amount": {
									"type": "string",
									"example": "150.50"
								},
								"from_address": {
									"type": "string",
									"nullable": true
								},
								"to_address": {
									"type": "string"
								}
							}
						}
					}
				}
			},
			"AssignedXlmWallet": {
				"type": "object",
				"properties": {
					"id": {
						"type": "string",
						"format": "uuid"
					},
					"address": {
						"type": "string",
						"description": "Shared Stellar deposit address (G...). The SAME for every XLM wallet — never use it alone to identify a wallet.",
						"example": "GCJAXR32J2VAFVCX4G32O52XNMT5XSKHOJ7V7XJE7CHIP3ZHU365LQAM"
					},
					"memo": {
						"type": "string",
						"description": "Decimal u64 memo id that identifies this wallet. Always a string (it exceeds the exact range of a JSON number). Payers must send it as memo type ID.",
						"example": "1234567890123456789"
					},
					"memo_type": {
						"type": "string",
						"enum": [
							"id"
						]
					},
					"muxed_address": {
						"type": "string",
						"description": "Muxed account (M...) = deposit address + memo in one string. Paying it needs no separate memo.",
						"example": "MCJAXR32J2VAFVCX4G32O52XNMT5XSKHOJ7V7XJE7CHIP3ZHU365KEJCCD2H32MBCWWVE"
					},
					"label": {
						"type": "string",
						"nullable": true
					},
					"status": {
						"type": "string",
						"enum": [
							"active",
							"inactive"
						]
					},
					"single_use": {
						"type": "boolean"
					},
					"created_at": {
						"type": "string",
						"format": "date-time"
					}
				}
			},
			"XlmWalletKeyRequest": {
				"type": "object",
				"description": "Identifies one of your XLM wallets. Send `memo` (string) or `muxed_address` (an `M...` passed as `address` is accepted too). The shared G address alone is rejected.",
				"properties": {
					"memo": {
						"type": "string",
						"example": "1234567890123456789"
					},
					"muxed_address": {
						"type": "string",
						"example": "MCJAXR32J2VAFVCX4G32O52XNMT5XSKHOJ7V7XJE7CHIP3ZHU365KEJCCD2H32MBCWWVE"
					}
				}
			},
			"XlmBalances": {
				"type": "object",
				"properties": {
					"XLM": {
						"$ref": "#/components/schemas/TonBalanceEntry"
					},
					"USDC": {
						"$ref": "#/components/schemas/TonBalanceEntry"
					}
				}
			},
			"XlmTransactionsRequest": {
				"type": "object",
				"properties": {
					"memo": {
						"type": "string",
						"description": "Filter by wallet memo (or send muxed_address)."
					},
					"muxed_address": {
						"type": "string"
					},
					"status": {
						"type": "string",
						"enum": [
							"detected",
							"confirmed",
							"notified",
							"swept"
						]
					},
					"limit": {
						"type": "integer",
						"default": 50,
						"maximum": 200
					},
					"offset": {
						"type": "integer",
						"default": 0
					}
				}
			},
			"XlmTransaction": {
				"type": "object",
				"properties": {
					"id": {
						"type": "string",
						"format": "uuid"
					},
					"tx_hash": {
						"type": "string",
						"description": "Stellar transaction hash (64 hex)."
					},
					"ledger": {
						"type": "integer",
						"description": "Ledger sequence the payment closed in."
					},
					"ledger_closed_at": {
						"type": "string",
						"format": "date-time",
						"nullable": true
					},
					"memo": {
						"type": "string",
						"description": "Memo id of the credited wallet."
					},
					"from_address": {
						"type": "string",
						"nullable": true
					},
					"to_address": {
						"type": "string",
						"description": "The shared deposit address."
					},
					"asset": {
						"type": "string",
						"enum": [
							"XLM",
							"USDC"
						]
					},
					"amount": {
						"type": "string",
						"description": "Human-readable decimal amount (7 decimals)."
					},
					"amount_raw": {
						"type": "string",
						"description": "Integer amount in stroops (1e-7), as a string."
					},
					"price_usd_at_detect": {
						"type": "number",
						"nullable": true,
						"description": "XLM spot at detection (null for USDC)."
					},
					"confirmations": {
						"type": "integer",
						"description": "Always 1 — closed Stellar ledgers are final."
					},
					"status": {
						"type": "string",
						"enum": [
							"detected",
							"confirmed",
							"notified",
							"swept"
						]
					},
					"webhook_sent": {
						"type": "boolean"
					},
					"created_at": {
						"type": "string",
						"format": "date-time"
					},
					"updated_at": {
						"type": "string",
						"format": "date-time"
					},
					"wallet_id": {
						"type": "string",
						"format": "uuid"
					}
				}
			},
			"XlmCheckHashRequest": {
				"type": "object",
				"required": [
					"tx_hash"
				],
				"properties": {
					"memo": {
						"type": "string",
						"example": "1234567890123456789"
					},
					"muxed_address": {
						"type": "string"
					},
					"tx_hash": {
						"type": "string",
						"pattern": "^[0-9a-fA-F]{64}$",
						"description": "Stellar transaction hash. Must be within the Stellar RPC retention window (about 7 days)."
					}
				}
			}
		},
		"responses": {
			"BadRequest": {
				"description": "Bad request — missing or invalid parameters",
				"content": {
					"application/json": {
						"schema": {
							"$ref": "#/components/schemas/ErrorResponse"
						},
						"example": {
							"error": "name and webhook_url are required"
						}
					}
				}
			},
			"Unauthorized": {
				"description": "Unauthorized — missing or invalid credentials",
				"content": {
					"application/json": {
						"schema": {
							"$ref": "#/components/schemas/ErrorResponse"
						},
						"example": {
							"error": "Invalid API key"
						}
					}
				}
			},
			"Forbidden": {
				"description": "Forbidden — client is deactivated",
				"content": {
					"application/json": {
						"schema": {
							"$ref": "#/components/schemas/ErrorResponse"
						},
						"example": {
							"error": "Client is deactivated"
						}
					}
				}
			},
			"NotFound": {
				"description": "Wallet not found or does not belong to this client",
				"content": {
					"application/json": {
						"schema": {
							"$ref": "#/components/schemas/ErrorResponse"
						},
						"example": {
							"error": "Wallet not found"
						}
					}
				}
			},
			"ServerError": {
				"description": "Internal server error",
				"content": {
					"application/json": {
						"schema": {
							"$ref": "#/components/schemas/ErrorResponse"
						},
						"example": {
							"error": "Internal server error"
						}
					}
				}
			},
			"TooManyRequests": {
				"description": "Per-client rate limit on live balance reads exceeded (1 request per minute per subsystem, shared with the dashboard variant of the route). Wait `Retry-After` seconds. Deposits are delivered by webhook; poll balances sparingly.",
				"headers": {
					"Retry-After": {
						"description": "Seconds until the window resets",
						"schema": {
							"type": "integer"
						}
					}
				},
				"content": {
					"application/json": {
						"schema": {
							"$ref": "#/components/schemas/ErrorResponse"
						},
						"example": {
							"error": "Rate limit exceeded: max 1 balance request per minute",
							"code": "RATE_LIMITED",
							"retry_after": 42
						}
					}
				}
			}
		}
	}
}
