# FAQ Source: https://docs.yellow.pro/account-and-balance/faq Quick answers about Yellow.pro balances, transfers, and locked funds. For Google Sign-in users, Account Balance (`Yellow Wallet`) is where deposits first arrive. Funds cannot be used for trading until transferred to the Trading Account (`Spot Account`). External wallet users do not have Account Balance — deposits go directly to the Trading Account. See [Understanding Your Balances](/account-and-balance/understanding-your-balances). Spot and Perpetual balances are completely separate. The Trading Account (`Spot Account`) is used for Spot trading, while the Perpetual Account is used only for perpetual futures positions. Funds do not transfer automatically between them — you must transfer manually via the Transfer feature. Google Sign-in users have an additional Account Balance (`Yellow Wallet`) layer where deposits arrive first. External wallet users' deposits go directly to the Trading Account (`Spot Account`), so no extra step is needed. See [Understanding Your Balances](/account-and-balance/understanding-your-balances). No. Funds in the Perpetual Account must be transferred back to the Trading Account (`Spot Account`) first, then (for Google Sign-in users) to Account Balance (`Yellow Wallet`) before withdrawal. See [How to Transfer Funds Between Accounts](/account-and-balance/transfer-funds-between-accounts). Account Balance ↔ Trading Account transfers are blockchain-based and may take time depending on network congestion. Trading Account ↔ Perpetual Account transfers are internal platform transfers and should be instant. See [Understanding Transfers on Yellow.pro](/account-and-balance/understanding-transfers). These are blockchain-based transfers subject to network congestion. They normally complete within a few minutes but can take significantly longer during high network activity. See [Understanding Transfers on Yellow.pro](/account-and-balance/understanding-transfers) if your transfer is still pending after 1 hour. Open the Perpetuals page (`yellow.pro/assets/perps`), click **Transfer**, and confirm the transfer from Perpetual Account to Trading Account (`Spot Account`). This is instant. See [How to Transfer Funds Between Accounts](/account-and-balance/transfer-funds-between-accounts). Open the Assets page (`yellow.pro/assets`), click **Transfer**, and select Trading Account (`Spot Account`) → Account Balance (`Yellow Wallet`). This is blockchain-based and may take time. See [How to Transfer Funds Between Accounts](/account-and-balance/transfer-funds-between-accounts). Yes. Check the Transfer page (`yellow.pro/assets/deposit/transfer`) for recent transfers, or transaction history (`yellow.pro/assets/history`) for the complete history. Blockchain-based transfers show a TxID once submitted. See [Understanding Transfers on Yellow.pro](/account-and-balance/understanding-transfers). Part of your balance is likely locked in open Spot orders or active perpetual positions. Only the available balance can be transferred or withdrawn. Close the related orders or positions to release the funds. See [Why Funds May Not Be Transferable](/account-and-balance/why-funds-not-transferable). Funds may be locked if they are used as margin for perpetual positions, locked in open Spot orders, still processing during a blockchain transfer, or in the wrong account type for what you're trying to do. See [Why Funds May Not Be Transferable](/account-and-balance/why-funds-not-transferable) for solutions. For Google Sign-in users, ensure the funds are not locked in open orders or positions, and check that the withdrawal amount meets the minimum requirement for that asset. See [Why Funds May Not Be Transferable](/account-and-balance/why-funds-not-transferable). It depends on your account type. Google Sign-in users route deposits through Account Balance (`Yellow Wallet`) before trading — and back through it to withdraw — while external wallet users deposit straight to the Trading Account (`Spot Account`). See the full deposit and withdrawal paths for both account types in [Understanding Your Balances](/account-and-balance/understanding-your-balances#how-funds-flow-through-your-balances). These are blockchain-based transfers, so network fees may apply — but they are sometimes sponsored by Yellow. You'll see whether a fee applies on the Transfer page. Provide your wallet address, the asset and amount involved, a screenshot of the transfer status or issue, and the TxID if it's visible. This helps the support team investigate faster. See [Contact Support](/community-and-resources/contact-support). # Overview Source: https://docs.yellow.pro/account-and-balance/overview Understand your balances and how to move funds between them. Learn how Yellow\.pro's balance areas work and how to move funds between them. Account Balance, Trading, and Perpetual accounts. Instant vs blockchain-based transfers. Step-by-step transfer guide. Locked funds and how to release them. Quick answers about balances and transfers. # How to Transfer Funds Between Accounts Source: https://docs.yellow.pro/account-and-balance/transfer-funds-between-accounts How to move funds between Account Balance, Trading Account, and Perpetual Account, and which transfers apply to your account type. Yellow\.pro lets you transfer funds between different account balances depending on your account type. This guide explains how to access transfers and which transfers apply to your account. ## Before You Start * Google Sign-in users can transfer between Account Balance (`Yellow Wallet`), Trading Account (`Spot Account`), and Perpetual Account. * External wallet users only transfer between Trading Account (`Spot Account`) and Perpetual Account. * Funds locked in open orders or active positions may not be available — see [Why Funds May Not Be Transferable](/account-and-balance/why-funds-not-transferable). For how long each transfer takes and how to track it, see [Understanding Transfers on Yellow.pro](/account-and-balance/understanding-transfers). ### Account Balance → Trading Account (`Spot Account`) **When to use:** moving deposited funds from Account Balance into the Trading Account so you can trade on Spot markets. 1. Open the Assets page: `yellow.pro/assets` 2. Click **Transfer**. 3. Select the asset and amount. 4. Confirm the transfer. Account Balance To Trading Account Transfer The window shows **From:** Account Balance (`Yellow Wallet`) → **To:** Trading Account (`Spot Account`). This is a blockchain-based transfer and may take time depending on network conditions. ### Trading Account → Account Balance (`Yellow Wallet`) **When to use:** moving funds back to Account Balance before withdrawing to your external wallet. 1. Open the Assets page: `yellow.pro/assets` 2. Click **Transfer**. 3. Select Account Balance as the destination. 4. Select the asset and amount. 5. Confirm the transfer. Perpetual Account -> Spot Account -> Account Balance Transfer This is also a blockchain-based transfer and may take time. ### Trading Account (`Spot Account`) ↔ Perpetual Account **When to use:** moving funds between Spot trading and perpetual trading. 1. Open the Perpetuals page: `yellow.pro/assets/perps` 2. Click **Transfer**. 3. Select the asset and amount. 4. Confirm the transfer. Transfer Between Trading (Spot) and Perpetual Account This is an internal platform transfer and normally reflects instantly. External wallet users do not use Account Balance (`Yellow Wallet`). The only available transfer is between Trading Account (`Spot Account`) and Perpetual Account. 1. Open the Perpetuals page: `yellow.pro/assets/perps` 2. Click **Transfer**. 3. Select the asset and amount. 4. Confirm the transfer. Trading (Spot Account) To Perpetual Account Transfer This transfer is internal and normally completes instantly. ## If a Transfer Doesn't Complete Internal Trading Account ↔ Perpetual Account transfers should be instant; blockchain-based Account Balance ↔ Trading Account transfers can stay pending during network congestion. For processing times, statuses, and step-by-step troubleshooting, see [Understanding Transfers on Yellow.pro](/account-and-balance/understanding-transfers). ## Related Articles * [Understanding Your Balances](/account-and-balance/understanding-your-balances) * [Understanding Transfers on Yellow.pro](/account-and-balance/understanding-transfers) * [Why Funds May Not Be Transferable](/account-and-balance/why-funds-not-transferable) # Understanding Transfers on Yellow.pro Source: https://docs.yellow.pro/account-and-balance/understanding-transfers Why some transfers are instant and others take time, how to check transfer status, and what to do if a transfer stays pending. Transfers on Yellow\.pro behave differently depending on which accounts are involved. Some transfers are instant, while others are blockchain-based and subject to network delays. This guide explains why transfers may take time and what to expect if a transfer stays pending. ## Before You Start * Account Balance (`Yellow Wallet`) ↔ Trading Account (`Spot Account`) transfers are blockchain-based and not instant. * Trading Account (`Spot Account`) ↔ Perpetual Account transfers are internal and should reflect instantly. * During blockchain congestion, transfers may take longer than usual. * If a blockchain-based transfer stays "Pending" for an extended period, the transaction may still be processing on-chain. For details on transfer types, see [Understanding Your Balances](/account-and-balance/understanding-your-balances). ## Why Transfers Take Time Blockchain-based transfers (Account Balance ↔ Trading Account) must wait for blockchain confirmations and are subject to network congestion. Internal transfers (Trading Account ↔ Perpetual Account) are instant because they happen entirely within the platform. **Expected timing:** Blockchain-based transfers usually complete within a few minutes under normal network conditions, but congestion can cause delays of 30 minutes or more. ## Checking Transfer Status You can track your transfers in two ways: * **Transfer page** (`yellow.pro/assets/deposit/transfer`) — shows recent transfers and their current status (Pending or Completed). Recent Transfers Records * **Transfer history** (`yellow.pro/assets/history`) — shows complete transfer history, displays the TxID once the blockchain transaction is submitted, and shows the final completion status. Transfer History For blockchain-based transfers, the TxID becomes visible once the transaction is submitted. You can use it to track progress on a blockchain explorer. ## Understanding Transfer Statuses
StatusMeaning
PendingTransfer is being processed on the blockchain. This is normal for Account Balance ↔ Trading Account transfers.
CompletedTransfer finished successfully. Funds are now in the destination account.
FailedTransfer could not be completed. Funds remain in the source account.
For blockchain-based transfers, "Pending" can last anywhere from a few minutes to several hours depending on network conditions. ## Why Is My Transfer Still Pending? This is usually normal while the blockchain transaction is being processed. Common reasons for delays: * blockchain network congestion * delayed transaction submission to the network * temporary blockchain confirmation delays Check the Transfer page or History to confirm the transfer is still showing as "Pending." If you see a TxID, you can also check a blockchain explorer to verify the status. **If the transfer remains pending for more than 1 hour:** 1. Verify which accounts are involved (confirm it's Account Balance ↔ Trading Account). 2. Check the Transfer page to confirm status. 3. If still pending, [contact support](/community-and-resources/contact-support) with your wallet address, the asset and amount, and a screenshot of the transfer status. These transfers should complete instantly. If the balance doesn't update immediately: 1. Refresh the page. 2. Disconnect and reconnect your wallet. 3. Retry the transfer. 4. Check whether the transfer status shows "Failed." If the issue persists, [contact support](/community-and-resources/contact-support) with your wallet address, the asset and amount, and a screenshot of the issue. ## Important Information * Funds locked in open orders, active positions, or used as margin may not be available for transfer until those orders or positions are closed. * For Google Sign-in users, think of Account Balance ↔ Trading Account transfers like standard blockchain deposits — they're not instant and depend on network conditions. ## Related Articles * [Understanding Your Balances](/account-and-balance/understanding-your-balances) * [How to Transfer Funds Between Accounts](/account-and-balance/transfer-funds-between-accounts) * [Why Funds May Not Be Transferable](/account-and-balance/why-funds-not-transferable) # Understanding Your Balances Source: https://docs.yellow.pro/account-and-balance/understanding-your-balances How Yellow.pro's balance areas work — Account Balance, Trading Account, and Perpetual Account — and how funds flow between them. Yellow\.pro uses different balance areas depending on how your account was created and what trading activity you're doing. Understanding these balances helps avoid confusion when depositing, transferring, and withdrawing funds. ## Account Types Determine Your Balance Structure Your account type affects which balances you use: * **Google Sign-in users** use three balances: Account Balance (`Yellow Wallet`), Trading Account (`Spot Account`), and Perpetual Account. * **External wallet users** use only two balances: Trading Account (`Spot Account`) and Perpetual Account. They do not use Account Balance. ## Account Balance (`Yellow Wallet`) **What it is:** For Google Sign-in users only. This is your smart contract wallet linked to your account. Deposits first arrive here before becoming available for trading. **What you can do with it:** * Receive incoming deposits * Hold funds before moving them to your Trading Account (`Spot Account`) * Process withdrawals (funds must be here before you can withdraw) Funds in Account Balance (`Yellow Wallet`) cannot be used directly for trading. They must first be transferred to your Trading Account (`Spot Account`). ## Trading Account (`Spot Account`) **What it is:** The balance where trading takes place. For Google Sign-in users, funds arrive here only after transferring from Account Balance (`Yellow Wallet`). For external wallet users, deposits arrive directly here. Trading (Spot) Account Balance **What you can do with it:** * Place trades on Spot markets * Transfer funds to the Perpetual Account for perpetual trading * Withdraw directly (external wallet users only) * Transfer back to Account Balance (`Yellow Wallet`) before withdrawal (Google Sign-in users only) ## Perpetual Account **What it is:** A separate balance used only for perpetual futures trading. Funds must be transferred here manually before they can be used for perpetual positions. Perpetual Account Balance **What you can do with it:** * Open and maintain perpetual trading positions * Hold margin for active positions Funds in the Perpetual Account cannot be withdrawn directly. They must be transferred back to the Trading Account (`Spot Account`) first, then to Account Balance (`Yellow Wallet`) before withdrawal. ## How Funds Flow Through Your Balances **Deposits** `External wallet or exchange → Account Balance (Yellow Wallet) → Trading Account (Spot Account) → Perpetual Account` **Withdrawals** `Perpetual Account → Trading Account (Spot Account) → Account Balance (Yellow Wallet) → Your external wallet` **Deposits** `External wallet → Trading Account (Spot Account) → Perpetual Account` **Withdrawals** `Perpetual Account → Trading Account (Spot Account) → External wallet` ## Moving Funds Between Balances How a transfer behaves depends on which balances are involved: **Account Balance ↔ Trading Account** transfers are blockchain-based and not instant, while **Trading Account ↔ Perpetual Account** transfers are internal and instant. For timing, statuses, and troubleshooting, see [Understanding Transfers on Yellow.pro](/account-and-balance/understanding-transfers); for step-by-step instructions, see [How to Transfer Funds Between Accounts](/account-and-balance/transfer-funds-between-accounts). ## Quick Comparison: Google Sign-in vs External Wallet | Feature | Google Sign-in Users | External Wallet Users | | --------------------------------------------- | --------------------------------------- | -------------------------------- | | Account Balance (`Yellow Wallet`) used? | Yes (required) | No | | Deposits arrive in | Account Balance (`Yellow Wallet`) | Trading Account (`Spot Account`) | | Extra transfer needed before trading? | Yes (Account Balance → Trading Account) | No | | Withdrawal process | Must transfer to Account Balance first | Direct from Trading Account | | Account Balance ↔ Trading Account transfers | Blockchain-based, not instant | Not applicable | | Trading Account ↔ Perpetual Account transfers | Instant, internal | Instant, internal | | Can withdraw directly from Perpetual Account? | No | No | ## Important Things to Know * Funds locked in open orders or active positions may not be available for transfer — see [Why Funds May Not Be Transferable](/account-and-balance/why-funds-not-transferable). * Account Balance ↔ Trading Account transfers may carry a network fee (sometimes sponsored by Yellow) — you'll see this on the Transfer page. * Blockchain transactions cannot be reversed once completed. ## Related Articles * [Understanding Transfers on Yellow.pro](/account-and-balance/understanding-transfers) * [How to Transfer Funds Between Accounts](/account-and-balance/transfer-funds-between-accounts) * [Why Funds May Not Be Transferable](/account-and-balance/why-funds-not-transferable) # Why Funds May Not Be Transferable Source: https://docs.yellow.pro/account-and-balance/why-funds-not-transferable Common reasons funds may appear in your balance but can't be transferred or withdrawn — and what to check before contacting support. Sometimes funds appear in your balance but are not available for transfer or withdrawal. This usually happens because the funds are currently being used elsewhere on the platform or are still processing. This guide explains the most common reasons and what to check before contacting support. ## Before You Start * Funds locked in open orders or positions cannot be transferred. * Perpetual trading uses a separate balance from Spot trading. * Google Sign-in users must use Account Balance (`Yellow Wallet`) for withdrawals. For how balances work, see [Understanding Your Balances](/account-and-balance/understanding-your-balances). For transfer timing and statuses, see [Understanding Transfers on Yellow.pro](/account-and-balance/understanding-transfers). ## Funds Locked in Spot Orders If you have active Spot trading orders, part of your balance may be locked for those orders. Locked funds cannot be transferred, withdrawn, or used elsewhere until the order is cancelled or completed. Locked Funds In Spot Orders **To make the funds transferable:** 1. Cancel the active order from the Spot trading page. 2. Wait for the balance to update (should be immediate). 3. Retry the transfer or withdrawal. ## Funds Locked as Perpetual Margin Funds being used as margin for perpetual positions are not available for transfer or withdrawal. This includes active perpetual positions that require margin, and margin committed to open perpetual orders (shown as **In Orders**). Locked Funds In Perpetual Orders **To release the funds:** 1. Close the open perpetual position. 2. Cancel the open perpetual order. 3. Wait for the margin balance to update. 4. Retry the transfer. Once the margin is released, the funds can be transferred back to the Trading Account (`Spot Account`). ## Funds Still Processing Between Accounts For Google Sign-in users, transfers between Account Balance (`Yellow Wallet`) and Trading Account (`Spot Account`) are blockchain-based. During processing, the transfer shows as "Pending," and the funds may temporarily not appear as available in either account. This is expected behavior during blockchain processing. **To check transfer status:** 1. Go to the Transfer page (`yellow.pro/assets/deposit/transfer`). 2. Look for your recent transfer and check its status. 3. Or check transaction history (`yellow.pro/assets/history`). If the transfer remains "Pending" for more than 1 hour, see [Understanding Transfers on Yellow.pro](/account-and-balance/understanding-transfers) for troubleshooting steps. ## Funds in the Wrong Account Sometimes funds are available but stored in a different balance than expected. Common scenarios: * Funds in the Perpetual Account cannot be withdrawn directly. * Funds in Account Balance (`Yellow Wallet`) cannot be used for Spot trading. * Funds in the Trading Account (`Spot Account`) cannot be withdrawn directly for Google Sign-in users. **To fix this:** make sure the funds are in the correct account before attempting the next action. Use the Transfer feature to move them — see [How to Transfer Funds Between Accounts](/account-and-balance/transfer-funds-between-accounts). ## Minimum Withdrawal Requirements Each asset has a minimum withdrawal amount. Withdrawals below the minimum cannot be initiated, and the withdrawal option may remain unavailable if your available balance is below the required minimum. For minimum amounts by asset, see the [How to Withdraw](/deposits-and-withdrawals/how-to-withdraw) guide. Minimum Amount For Withdrawal ## Summary Funds may not be transferable if they are: * locked in active Spot orders * being used as perpetual margin * still processing during a blockchain transfer * stored in a different account type than needed * below the minimum withdrawal amount Checking the balance location, transfer status, and open trading activity usually resolves most transfer-related confusion. ## Related Articles * [Understanding Your Balances](/account-and-balance/understanding-your-balances) * [How to Transfer Funds Between Accounts](/account-and-balance/transfer-funds-between-accounts) * [Understanding Transfers on Yellow.pro](/account-and-balance/understanding-transfers) # Account Transfers API Source: https://docs.yellow.pro/api-and-programmatic-access/account-transfers-api Transfer funds between spot and perpetuals accounts via the API. The account transfer API provides an endpoint for transferring funds between spot and perpetuals accounts. A transfer request returns `202 Accepted` when the request is accepted; you are notified of completion on the `transfer_updates` WebSocket channel. ## POST /accounts/transfer Initiate a fund transfer between spot and perpetuals accounts. The request returns `202 Accepted` when accepted, and you are notified of completion on the `transfer_updates` WebSocket channel. **Authentication:** Required (JWT or API Key) **Request Body**: ```json theme={null} { "app_session_id": "your-session-id", "source_account_type": "spot", "dest_account_type": "perps", "asset_symbol": "USDT", "amount": "1000.50" } ``` **Request Parameters**: | Parameter | Type | Required | Options | Description | | --------------------- | ------ | -------- | ---------------- | ----------------------------------------------------------------------------------------------------------------------------- | | `app_session_id` | string | Yes | — | User's session ID (shared between spot and perps accounts) | | `source_account_type` | string | Yes | `spot`, `perps` | Source account type | | `dest_account_type` | string | Yes | `spot`, `perps` | Destination account type | | `asset_symbol` | string | Yes | — | Stablecoin asset to transfer (e.g., "USDT"). Only stablecoin assets that are active on both spot and perps sides are allowed. | | `amount` | string | Yes | Positive decimal | Amount to transfer (decimal format) | **Asset Restrictions**: * Only **stablecoin** assets can be transferred between spot and perps accounts. * The asset must be active as a stablecoin on both the spot and perps sides. * Use `GET /perpetual/transfer-assets` to fetch the list of transferable stablecoin assets. **Perpetual → Spot (perps as source)**: When transferring from a perps account to spot, the maximum transferable amount is capped per request: `transferable_max = max(0, min(total_balance - locked_balance, available_balance)) × 80%` * `available_balance` follows balance-query semantics (it includes unrealized PnL where applicable). * If `amount` exceeds `transferable_max`, the transfer is rejected with an insufficient-balance error. **Balance Notifications**: * After a successful transfer, both the source and destination accounts emit balance update events over WebSocket so clients can refresh displayed balances without polling. * Spot balance updates are delivered on the `spot_account.balance_update` channel. * Perps balance updates are delivered on the `perpetuals_account.balance_update` channel. **Response** (202 Accepted): ```json theme={null} { "transfer_id": "550e8400-e29b-41d4-a716-446655440000", "message": "Transfer initiated successfully. You will be notified when the transfer completes." } ``` **Response Fields**: | Field | Type | Description | | ------------- | ------ | ------------------------------------- | | `transfer_id` | string | Unique UUID for tracking the transfer | | `message` | string | Human-readable status message | **Status Codes**: * `202` - Transfer request accepted and queued for processing * `400` - Invalid request parameters (non-stablecoin asset, invalid amount, etc.) * `401` - Authentication failed (missing or invalid JWT/API key) * `500` - Internal server error * `503` - Transfer validation service temporarily unavailable **Error Responses**: **400 Bad Request** - Invalid parameters: ```json theme={null} { "error": "invalid_amount", "message": "Amount must be positive" } ``` Possible error codes: * `invalid_request_format` - Malformed JSON or missing required fields * `invalid_amount` - Amount is zero, negative, or invalid decimal * `invalid_source_type` - Source account type must be 'spot' or 'perps' * `invalid_dest_type` - Destination account type must be 'spot' or 'perps' * `same_account_type` - Source and destination types cannot be the same * `invalid_asset` - Asset is not supported for spot-perps transfer (not a stablecoin, not active, or not found) * `amount_below_minimum` - Amount is below minimum transfer amount for the asset **401 Unauthorized**: ```json theme={null} { "error": "missing_wallet_address", "message": "Wallet address not found in authentication context" } ``` **500 Internal Server Error**: ```json theme={null} { "error": "transfer_failed", "message": "Failed to initiate transfer. Please try again or contact support." } ``` **Transfer Lifecycle**: After a transfer is accepted: 1. The request is validated and accepted, returning `202 Accepted` with a `transfer_id`. 2. Funds are debited from the source account, then credited to the destination account. 3. When the transfer completes (or fails), the client is notified in real time on the `transfer_updates` WebSocket channel. **Transfer States**: | State | Description | | ------------------ | -------------------------------------------------------- | | `pending` | Transfer initiated, waiting for source processing | | `source_completed` | Funds deducted from source account | | `dest_completed` | Funds added to destination account (final success state) | | `failed` | Transfer failed before any funds were moved | **WebSocket Notification**: When the transfer completes (or fails), you receive a real-time notification: ```json theme={null} { "channel": "transfer_updates", "data": { "transfer_id": "550e8400-e29b-41d4-a716-446655440000", "owner_address": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb", "app_session_id": "your-session-id", "source_type": "spot", "dest_type": "perps", "asset_symbol": "USDT", "amount": "1000.50", "state": "dest_completed", "completed_at": "2026-02-16T10:30:45.123456Z" } } ``` **Important Notes**: * **Stablecoin Only**: Only stablecoin assets that are active on both the spot and perps sides can be transferred * **Perp → Spot cap**: Outgoing perpetuals transfers are limited per request to 80% of `min(total - locked, available)` (see **Perpetual → Spot** above); plan `amount` accordingly or split into multiple transfers * **Real-time Updates**: Subscribe to WebSocket `transfer_updates` channel for completion notifications. Balance update notifications are also pushed to `spot_account.balance_update` and `perpetuals_account.balance_update` channels. * **Source and destination types must be different** (cannot transfer within the same account type) **Example Request**: ```bash theme={null} curl -X POST https://trade.api.yellow.pro/accounts/transfer \ -H "Authorization: Bearer YOUR_JWT_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "app_session_id": "your-session-id", "source_account_type": "spot", "dest_account_type": "perps", "asset_symbol": "USDT", "amount": "1000.00" }' ``` # API Key Management Source: https://docs.yellow.pro/api-and-programmatic-access/api-key-management Create, list, and revoke API keys, with scopes and IP allow-lists. API keys let you call authenticated endpoints from servers and scripts. You create and manage keys through these endpoints, then sign each request as described in [Signing Requests With API Keys](/api-and-programmatic-access/signing-requests-with-api-keys). API key management endpoints require **JWT authentication** — obtain a JWT first via the [Authentication Service API](/api-and-programmatic-access/authentication-service-api). You cannot manage API keys using API key headers; doing so returns `403 forbidden_auth_method`. ## Scopes Each key is granted one or more scopes. Requests signed with a key are limited to the actions its scopes allow. | Scope | Grants | | --------------- | --------------------------------------------------------- | | `read:spot` | Read spot accounts, orders, trades, deposits, withdrawals | | `trade:spot` | Place and cancel spot orders | | `withdraw:spot` | Request spot withdrawals | | `read:futures` | Read perpetuals accounts, positions, orders, trades | | `trade:futures` | Place and cancel perpetuals orders, manage positions | Grant the narrowest set of scopes a key needs. A read-only data key should not carry `trade:*` or `withdraw:*` scopes. ## GET /accounts/api-keys List the API keys belonging to the authenticated account. **Authentication:** Required (JWT only) **Query Parameters**: | Parameter | Type | Required | Options | Description | | ----------- | ------- | -------- | ------------------------ | -------------- | | `page` | integer | No | default `1` | Page number | | `page_size` | integer | No | capped at server maximum | Items per page | **Response**: ```json theme={null} { "keys": [ { "id": "key_550e8400e29b41d4", "api_key": "ak_live_1234567890abcdef", "scopes": ["read:spot", "trade:spot"], "ip_whitelist": ["203.0.113.10"], "state": "active", "expires_at": "2027-01-01T00:00:00Z", "last_used_at": "2026-06-10T09:30:00Z", "created_at": "2026-06-01T12:00:00Z", "description": "trading bot" } ], "total": 1, "page": 1, "page_size": 50 } ``` **Response Fields**: | Field | Type | Description | | --------------------- | ------- | --------------------------------------------------------- | | `keys` | array | Array of API key records | | `keys[].id` | string | Internal key identifier (used to revoke the key) | | `keys[].api_key` | string | The public API key value (sent in the `X-API-KEY` header) | | `keys[].scopes` | array | Granted scopes | | `keys[].ip_whitelist` | array | Allowed source IPs (empty means no IP restriction) | | `keys[].state` | string | Key state (e.g. `active`, `revoked`) | | `keys[].expires_at` | string | Expiry timestamp, or empty if the key does not expire | | `keys[].last_used_at` | string | Last time the key was used, or empty if never used | | `keys[].created_at` | string | Creation timestamp | | `keys[].description` | string | User-supplied label | | `total` | integer | Total number of keys | | `page` | integer | Pagination echo | | `page_size` | integer | Pagination echo | **Status Codes**: * `200` - Keys retrieved successfully * `401` - Authentication failed * `403` - Request was not authenticated with a JWT (`forbidden_auth_method`) ## POST /accounts/api-keys Create a new API key. The **secret is returned only once**, in this response — store it immediately; it cannot be retrieved later. **Authentication:** Required (JWT only) **Request Body**: ```json theme={null} { "scopes": ["read:spot", "trade:spot"], "ip_whitelist": ["203.0.113.10"], "expires_at": "2027-01-01T00:00:00Z", "description": "trading bot" } ``` **Request Parameters**: | Parameter | Type | Required | Options | Description | | -------------- | ------ | -------- | ------- | ----------------------------------------------------------------------------- | | `scopes` | array | Yes | — | Scopes to grant (see [Scopes](#scopes)) | | `ip_whitelist` | array | No | — | Source IPs allowed to use the key. Omit or leave empty for no IP restriction. | | `expires_at` | string | No | RFC3339 | Expiry timestamp. Omit for a non-expiring key. | | `description` | string | No | — | A label to help you identify the key | **Response** (`201 Created`): ```json theme={null} { "key": { "id": "key_550e8400e29b41d4", "api_key": "ak_live_1234567890abcdef", "scopes": ["read:spot", "trade:spot"], "ip_whitelist": ["203.0.113.10"], "state": "active", "expires_at": "2027-01-01T00:00:00Z", "last_used_at": "", "created_at": "2026-06-10T12:00:00Z", "description": "trading bot" }, "secret": "as_live_abcdef1234567890abcdef1234567890" } ``` **Response Fields**: | Field | Type | Description | | -------- | ------ | ------------------------------------------------------------------------ | | `key` | object | The created key record (same shape as in the list response) | | `secret` | string | The API secret, used to compute request signatures. **Shown only once.** | Store the `secret` securely the moment you receive it. It is never returned again, and it must never be committed to version control or exposed in client-side code. **Status Codes**: * `201` - Key created successfully * `400` - Invalid request body or invalid scope/parameter * `401` - Authentication failed * `403` - Request was not authenticated with a JWT (`forbidden_auth_method`) * `500` - Internal server error ## POST /accounts/api-keys/:id/revoke Revoke an API key by its `id`. Revocation is immediate and permanent; the key can no longer be used to sign requests. **Authentication:** Required (JWT only) **Path Parameters**: | Parameter | Type | Required | Options | Description | | --------- | ------ | -------- | ------- | ------------------------------------------------------ | | `id` | string | Yes | — | The `id` of the key to revoke (from the list response) | **Response**: ```json theme={null} { "message": "API key revoked" } ``` **Status Codes**: * `200` - Key revoked successfully * `401` - Authentication failed * `403` - Request was not authenticated with a JWT (`forbidden_auth_method`) * `404` - Key not found or not owned by the authenticated account (`api_key_not_found`) ## Next step Once you have an API key and secret, see [Signing Requests With API Keys](/api-and-programmatic-access/signing-requests-with-api-keys) to authenticate your requests. # Authentication Service API Source: https://docs.yellow.pro/api-and-programmatic-access/authentication-service-api Authentication service endpoints: challenge, verify, refresh, login, logout, and /auth/me. ## Health Endpoints ### GET /health Check if the authentication service is running and healthy. **Authentication:** Not required **Response**: ```json theme={null} { "status": "UP" } ``` **Status Codes**: * `200` - Service is healthy * `500` - Service is unhealthy ## Authentication Endpoints ### POST /auth/challenge Generate a unique authentication challenge for wallet signature verification. **Authentication:** Not required **Request Body**: ```json theme={null} { "wallet_address": "0x1234567890abcdef1234567890abcdef12345678" } ``` **Request Parameters**: | Parameter | Type | Required | Options | Description | | ---------------- | ------ | -------- | -------------------------- | ----------------------- | | `wallet_address` | string | Yes | 0x-prefixed, 42 characters | Ethereum wallet address | **Response**: ```json theme={null} { "challenge": "Yellow Challenge: 1234567890abcdef, Timestamp: 2023-12-07T10:30:00Z, Nonce: 1234567890abcdef1234567890abcdef", "expires_at": "2023-12-07T10:35:00Z" } ``` **Response Fields**: | Field | Type | Description | | ------------ | ------ | ------------------------------------------------------- | | `challenge` | string | The challenge text that must be signed with your wallet | | `expires_at` | string | When the challenge expires (ISO 8601 format) | **Status Codes**: * `200` - Challenge generated successfully * `400` - Invalid wallet address or request format * `429` - Rate limit exceeded * `500` - Internal server error ### POST /auth/verify Verify the signature of a challenge and issue JWT tokens. **Authentication:** Not required **Request Body**: ```json theme={null} { "wallet_address": "0x1234567890abcdef1234567890abcdef12345678", "challenge": "Yellow Challenge: 1234567890abcdef, Timestamp: 2023-12-07T10:30:00Z, Nonce: 1234567890abcdef1234567890abcdef", "signature": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef12" } ``` **Request Parameters**: | Parameter | Type | Required | Options | Description | | ---------------- | ------ | -------- | --------------------------- | -------------------------------------- | | `wallet_address` | string | Yes | — | Same wallet address used for challenge | | `challenge` | string | Yes | — | The challenge text that was generated | | `signature` | string | Yes | 0x-prefixed, 132 characters | Ethereum signature of the challenge | **Response**: ```json theme={null} { "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...", "refresh_token": "rt_1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef", "expires_in": 900, "token_type": "Bearer" } ``` **Response Fields**: | Field | Type | Description | | --------------- | ------- | ------------------------------------- | | `access_token` | string | JWT token for API authentication | | `refresh_token` | string | Token for refreshing the access token | | `expires_in` | integer | Access token lifetime in seconds | | `token_type` | string | Always "Bearer" | **Status Codes**: * `200` - Signature verified successfully, tokens issued * `400` - Invalid request format * `401` - Invalid signature or expired challenge * `429` - Rate limit exceeded * `500` - Internal server error ### POST /auth/refresh Generate a new access token using a valid refresh token. **Authentication:** Not required **Request Body**: ```json theme={null} { "refresh_token": "rt_1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef" } ``` **Request Parameters**: | Parameter | Type | Required | Options | Description | | --------------- | ------ | -------- | ---------------------------- | ------------------- | | `refresh_token` | string | Yes | rt\_ prefixed, 67 characters | Valid refresh token | **Response**: ```json theme={null} { "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...", "refresh_token": "rt_9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba", "expires_in": 900, "token_type": "Bearer" } ``` **Status Codes**: * `200` - Token refreshed successfully * `400` - Invalid request format * `401` - Invalid or expired refresh token * `429` - Rate limit exceeded (20 requests per minute) * `500` - Internal server error ### POST /auth/logout Invalidate the current session by blacklisting it and revoking all associated refresh tokens. **Authentication:** Required **Response**: ```json theme={null} { "message": "Successfully logged out" } ``` **Status Codes**: * `200` - Successfully logged out * `401` - Missing or invalid access token * `429` - Rate limit exceeded * `500` - Internal server error ### GET /auth/me Retrieve information about the authenticated user from their JWT token. **Authentication:** Required **Response**: ```json theme={null} { "wallet_address": "0x1234567890abcdef1234567890abcdef12345678", "session_id": "550e8400-e29b-41d4-a716-446655440000", "token_id": "550e8400-e29b-41d4-a716-446655440001", "issued_at": 1701938200, "expires_at": 1701939100 } ``` **Response Fields**: | Field | Type | Description | | ---------------- | ------- | --------------------------------------- | | `wallet_address` | string | User's Ethereum wallet address | | `session_id` | string | Current session identifier | | `token_id` | string | Current token identifier (JTI) | | `issued_at` | integer | Token issued timestamp (Unix epoch) | | `expires_at` | integer | Token expiration timestamp (Unix epoch) | **Status Codes**: * `200` - User information retrieved successfully * `401` - Missing or invalid access token * `429` - Rate limit exceeded * `500` - Internal server error # Error Handling API Source: https://docs.yellow.pro/api-and-programmatic-access/error-handling-api Error response formats, codes, and HTTP statuses across the Yellow.pro API. All endpoints return consistent error responses with the following structure: ## Authentication Service Errors ```json theme={null} { "error": "error_code", "message": "Human-readable error message", "code": 400 } ``` ## Trading API Service Errors ```json theme={null} { "error": "error_code", "message": "Detailed error description" } ``` ## Common Error Codes ### Authentication Service * `invalid_request` - Invalid request body format * `invalid_wallet_address` - Invalid Ethereum wallet address * `internal_error` - Internal server error * `challenge_expired` - Challenge not found or expired * `invalid_signature` - Signature verification failed * `invalid_refresh_token` - Refresh token invalid or expired * `missing_token` - Authorization header missing * `invalid_token_format` - Invalid Authorization header format * `unauthorized` - Authentication required ### Trading API Service Order and leverage endpoints (`POST /spot/order`, `POST /perpetual/order`, `POST /perpetual/leverage`) may return a snake\_case `error` code describing why the request was rejected (for example, insufficient balance). When no specific code applies to a rejected fund reservation, `lock_funds_rejected` is returned. #### General Trading API codes * `missing_parameter` - Required parameter is missing * `invalid_request_format` - Request body format is invalid * `validation_failed` - Request validation failed (common on perpetual order and other endpoints) * `order_creation_failed` - Spot order creation failed (message carries detail) * `lock_funds_rejected` - The funds could not be reserved for this order (typically insufficient available balance) * `missing_channel_id` - Channel ID parameter is required * `missing_symbol` - Symbol parameter is required * `symbol_not_found` - Requested symbol not found * `missing_order_uuid` - Order UUID is required * `invalid_order_uuid` - Order UUID format is invalid * `internal_error` - Internal server error occurred #### Spot order placement errors * `service_unavailable` - Spot service is unavailable * `invalid_amount` - Amount is invalid or non-positive * `invalid_price` - Price is invalid * `invalid_side` - Side is not buy/sell * `no_permitted` - Caller is not the account owner * `account_not_active` - Spot account is not active * `account_not_exists` - Account not found * `insufficient_balance` - Not enough available balance to reserve * `market_price_unavailable` - No usable market price (e.g. market order) or reference price issue * `market_not_found` - Unknown market symbol * `unsupported_order_type` - Order type not supported for this request * `missing_limit_price` - Limit order requires a non-zero price * `limit_price_deviation_exceeded` - Limit price outside max deviation vs reference * `fee_rate_unavailable` - Could not resolve maker/taker fee rate * `lock_failed` - Could not reserve funds (see `message`) #### Spot order cancellation errors * `service_unavailable` - Spot service is unavailable * `invalid_amount` - Amount is invalid, non-positive, or an invalid delta * `insufficient_locked_balance` - Cannot release more than was reserved * `unlock_failed` - Could not release funds (see `message`) #### Perpetual order placement errors * `service_unavailable` - Perpetuals service is unavailable * `invalid_amount` - Amount is invalid, non-positive, or truncated to zero * `invalid_leverage_value` - Request leverage not a number ≥ 1 * `leverage_exceeds_max` - Leverage above market maximum * `invalid_side` - Side is not buy/sell * `invalid_direction` - Direction not long or short * `account_not_exists` - Account not found * `no_permitted` - Caller is not the account owner * `account_locked_for_liquidation` - Cross account locked for liquidation * `fee_rate_unavailable` - Could not load maker/taker fee rate * `no_position_to_close` - Closing order but no position * `position_locked_for_liquidation` - Position locked for liquidation * `insufficient_position` - Close size exceeds available position * `mark_price_unavailable` - Mark price needed but unavailable * `invalid_limit_price` - Limit price missing or non-positive * `limit_price_deviation_exceeded` - The limit price is too far from the reference (mark) price * `insufficient_margin_for_fees` - Not enough margin for closing fees * `lock_position_failed` - Failed to lock position quantity * `initial_margin_calculation_failed` - Initial margin computation failed * `insufficient_margin` - Not enough margin for open (margin + fees) * `lock_margin_failed` - Failed to reserve margin #### Set leverage errors * `missing_app_session_id` - `app_session_id` is empty * `missing_market` - `market` is empty * `missing_user_address` - `user_address` is empty * `service_unavailable` - Perpetuals service is unavailable * `invalid_leverage_value` - Leverage is not a number ≥ 1 * `leverage_exceeds_max` - Above market max leverage * `account_not_exists` - Account not found * `no_permitted` - Caller is not the account owner * `account_not_active` - Account not active * `open_orders_check_failed` - Could not verify open orders * `order_exists` - Open orders exist for this market * `insufficient_balance` - Not enough available collateral to apply higher leverage when positions require extra margin * `leverage_exceeds_safe_margin` - New leverage would put allocated margin below the maintenance buffer for a position * `set_leverage_failed` - Could not update leverage ## HTTP Status Codes * `200` - Success * `400` - Bad Request (client error) * `401` - Unauthorized (authentication required/failed) * `404` - Not Found (resource doesn't exist) * `500` - Internal Server Error # Getting Started with API Source: https://docs.yellow.pro/api-and-programmatic-access/getting-started-with-api Authenticate with the Yellow.pro API and start calling endpoints. This guide walks you through authenticating with the Yellow\.pro API so you can start calling endpoints. All trading, account, and transfer endpoints require authentication. Market data endpoints are public and need no credentials. For API base URLs, see [Base URLs](/api-and-programmatic-access/overview#base-urls). ## Authentication Flow Yellow\.pro uses Ethereum wallet-based authentication with a challenge-response mechanism: POST to `/auth/challenge` with your wallet address. Sign the returned challenge text with your Ethereum wallet. POST to `/auth/verify` with your wallet address, the challenge, and the signature. Get a JWT access token and a refresh token for API access. Include the JWT in the `Authorization` header on authenticated endpoints. ```http theme={null} Authorization: Bearer ``` See the [Authentication Service API](/api-and-programmatic-access/authentication-service-api) for full request and response details on each endpoint. ## Authentication Methods All authenticated endpoints support two authentication methods. Obtained via the `/auth/verify` endpoint. Include the token in the `Authorization` header: ```http theme={null} Authorization: Bearer ``` Supported by all authenticated endpoints. Best suited for programmatic / server-side access where you don't want to manage a wallet signing flow on every request. Each request includes three headers: ```http theme={null} X-API-KEY: X-TIMESTAMP: X-SIGNATURE: ``` * Supported by all authenticated endpoints (spot, perpetuals, transfers) * Automatically falls back to JWT if API key headers are not present See [**Signing Requests With API Keys**](/api-and-programmatic-access/signing-requests-with-api-keys) for the exact signature algorithm and ready-to-use Node.js and Python examples. Never commit API keys or secrets to version control. Store them in environment variables or a secrets manager. ## Security Notes * Access tokens expire in 15 minutes * Refresh tokens expire in 7 days * Sessions can be invalidated via logout * Rate limiting is enforced on authentication endpoints ## Next Steps Create an API key | Section | Description | Target | | ---------------------------------- | ----------------------------------------- | --------------------------------------------------------------------------------------------- | | **API Key Management** | Create, list, and revoke API keys | [API Key Management](/api-and-programmatic-access/api-key-management) | | **Signing Requests with API Keys** | HMAC-SHA256 signing with code examples | [Signing Requests with API Keys](/api-and-programmatic-access/signing-requests-with-api-keys) | | **Market Data API** | Prices and indicators (no auth required) | [Market Data API](/api-and-programmatic-access/market-data-api) | | **Spot Trading** | Place and manage spot orders | [Spot Trading API](/api-and-programmatic-access/spot-trading-api) | | **Perpetuals Trading** | Positions, leverage, and perpetual orders | [Perpetuals Trading API](/api-and-programmatic-access/perpetuals-trading-api) | # Market Data API Source: https://docs.yellow.pro/api-and-programmatic-access/market-data-api Public market-data endpoints for prices, indicators, and market analysis. These endpoints provide real-time market data for prices, technical indicators, and market analysis. Base URL: see [Base URLs](/api-and-programmatic-access/overview#base-urls). ## Health Endpoints ### GET /health Check if the market data service is running and healthy. **Authentication:** Not required **Response**: ```json theme={null} { "status": "UP" } ``` **Status Codes**: * `200` - Service is healthy * `500` - Service is unhealthy ## Market Data Endpoints ### GET /data/price Retrieve the latest price observation for all markets. **Authentication:** Not required **Response**: ```json theme={null} { "header": { "event_id": "550e8400-e29b-41d4-a716-446655440000", "timestamp": "2023-12-07T10:30:00Z" }, "market": "BTCUSD", "price": "35000.50000000" } ``` **Response Fields**: | Field | Type | Description | | ------------------ | ------ | ------------------------------ | | `header` | object | Event metadata | | `header.event_id` | string | Unique event identifier | | `header.timestamp` | string | Event timestamp | | `market` | string | Market symbol (e.g., "BTCUSD") | | `price` | string | Latest observed price | **Status Codes**: * `200` - Latest price retrieved successfully * `204` - No price data available * `500` - Internal server error ### GET /data/momentum Retrieve the latest momentum indicator data for all markets. **Authentication:** Not required **Request**: ```http theme={null} GET /data/momentum ``` **Response**: ```json theme={null} { "Market": { "Base": "btc", "Quote": "usd" }, "Value": "0.0023", "Time": "2025-09-30T15:40:54.455631184Z" } ``` **Response Fields**: | Field | Type | Description | | -------------- | ------ | ----------------------------------------------------------- | | `Market` | object | Market information | | `Market.Base` | string | Base currency (e.g., "btc") | | `Market.Quote` | string | Quote currency (e.g., "usd") | | `Value` | string | Momentum indicator value (decimal) | | `Time` | string | Timestamp when the indicator was computed (ISO 8601 format) | **Status Codes**: * `200` - Latest momentum retrieved successfully * `204` - No momentum data available * `500` - Internal server error ### GET /data/std Retrieve the latest moving standard deviation data for all markets. **Authentication:** Not required **Request**: ```http theme={null} GET /data/std ``` **Response**: ```json theme={null} { "Market": { "Base": "btc", "Quote": "usd" }, "Value": "145.67", "Time": "2025-09-30T15:40:54.455631184Z" } ``` **Response Fields**: | Field | Type | Description | | -------------- | ------ | ----------------------------------------------------------- | | `Market` | object | Market information | | `Market.Base` | string | Base currency (e.g., "btc") | | `Market.Quote` | string | Quote currency (e.g., "usd") | | `Value` | string | Moving standard deviation value (decimal) | | `Time` | string | Timestamp when the indicator was computed (ISO 8601 format) | **Status Codes**: * `200` - Latest standard deviation retrieved successfully * `204` - No standard deviation data available * `500` - Internal server error ### GET /data/vwma Retrieve the latest volume-weighted moving average (VWMA) data for all markets. **Authentication:** Not required **Request**: ```http theme={null} GET /data/vwma ``` **Response**: ```json theme={null} { "Market": { "Base": "btc", "Quote": "usd" }, "Value": "35250.45", "Time": "2025-09-30T15:40:54.455631184Z" } ``` **Response Fields**: | Field | Type | Description | | -------------- | ------ | ----------------------------------------------------------- | | `Market` | object | Market information | | `Market.Base` | string | Base currency (e.g., "btc") | | `Market.Quote` | string | Quote currency (e.g., "usd") | | `Value` | string | Volume-weighted moving average value (decimal) | | `Time` | string | Timestamp when the indicator was computed (ISO 8601 format) | **Status Codes**: * `200` - Latest VWMA retrieved successfully * `204` - No VWMA data available * `500` - Internal server error # Overview Source: https://docs.yellow.pro/api-and-programmatic-access/overview Overview of the Yellow.pro REST and WebSocket APIs, base URLs, and authentication. The Yellow\.pro platform provides REST and WebSocket APIs for authentication, trading, account management, and market data. There are two base URLs: * **Authentication API** — wallet-based authentication, JWT tokens, and session management * **Trading API** — trading, positions, transfers, market data, and the WebSocket stream New here? Start with [**Getting Started with API**](/api-and-programmatic-access/getting-started-with-api) to authenticate and obtain your API keys. ## Base URLs | API | Base URL | | ---------------------------- | ------------------------------ | | Authentication | `https://auth.api.yellow.pro` | | Trading (REST + market data) | `https://trade.api.yellow.pro` | | WebSocket | `wss://trade.api.yellow.pro` | All examples in these docs use the production hosts above. Market data endpoints are served from the Trading API base URL and require no authentication. ## Contents Authentication flow, JWT and API key (HMAC) auth Create, list, and revoke API keys; scopes and IP allow-lists HMAC-SHA256 signature algorithm with Node.js and Python examples Challenge, verify, refresh, login, logout, /auth/me Health, auth testing, and exchange market data Prices, momentum, std, VWMA (no auth required) Spot accounts, orders, trades, deposits, withdrawals Positions, leverage, margin, perp orders, funding Internal transfers and send history Real-time streams and liquidation warnings Error response formats, codes, HTTP statuses Rate limits, data types, implementation notes # Perpetuals Trading API Source: https://docs.yellow.pro/api-and-programmatic-access/perpetuals-trading-api Perpetuals API: positions, orders, leverage, margin, funding, and history. The perpetuals trading API provides endpoints for managing cross-margin perpetual futures accounts, placing and canceling orders, monitoring positions, and retrieving trade history. All perpetuals accounts use cross-margin model where collateral is shared across all positions. ## GET /perpetual/exchangeInfo Retrieve exchange information for perpetuals markets including available markets and their details. **Authentication:** Not required **`maker_fee_rate` and `taker_fee_rate` here are outdated.** The values returned in `exchangeInfo` are static, indicative defaults and do **not** reflect the fees actually applied to your account (fee tiers, promotions, etc.). For the authoritative, account-specific rates always use [`GET /perpetual/account/market-fee-rate`](#get-perpetual-account-market-fee-rate). **Response**: ```json theme={null} { "timezone": "UTC", "server_time": 1640995200000, "symbols": [ { "symbol": "BTCYTEST.USD-PERP", "status": "active", "base_asset_name": "Bitcoin", "base_asset": "BTC", "quote_asset_name": "US Dollar", "quote_asset": "USD", "amount_precision": 8, "price_precision": 8, "amount_display_precision": 8, "price_display_precision": 8, "maker_fee_rate": "0.001", "taker_fee_rate": "0.002", "max_allowed_leverage": "100", "maintenance_margin_rate": "0.007", "filters": [ {"filter_type": "PRICE_FILTER", "config": {"tick_size": "0.01", "price_min_ratio": "0.9", "price_max_ratio": "1.1"}}, {"filter_type": "LOT_SIZE", "config": {"step_size": "0.001", "min_qty": "0.001", "max_qty": "999999999"}}, {"filter_type": "MIN_NOTIONAL", "config": {"min_notional": "1"}}, {"filter_type": "DEPTH_MERGE", "config": {"depth_level": ["0.001", "0.01", "0.1", "1"]}} ] } ] } ``` **Response Fields**: | Field | Type | Description | | ------------------------------------ | -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `timezone` | string | Exchange timezone | | `server_time` | integer | Current server timestamp in milliseconds | | `symbols` | array | Array of available perpetuals markets | | `symbols[].symbol` | string | Trading symbol name (e.g., "BTCYTEST.USD-PERP") | | `symbols[].status` | string | Market status (e.g., "active") | | `symbols[].base_asset_name` | string | Display name for base asset | | `symbols[].base_asset` | string | Base asset symbol (e.g., "BTC") | | `symbols[].quote_asset_name` | string | Display name for quote asset | | `symbols[].quote_asset` | string | Quote asset symbol (e.g., "USD") | | `symbols[].amount_precision` | integer | Decimal precision for amount (base asset) | | `symbols[].price_precision` | integer | Decimal precision for price (quote asset) | | `symbols[].amount_display_precision` | integer | Display precision for amount in UI | | `symbols[].price_display_precision` | integer | Display precision for price in UI | | `symbols[].maker_fee_rate` | decimal string | ⚠️ **Outdated** — static indicative default, not your account's effective rate. Use [`GET /perpetual/account/market-fee-rate`](#get-perpetual-account-market-fee-rate). | | `symbols[].taker_fee_rate` | decimal string | ⚠️ **Outdated** — static indicative default, not your account's effective rate. Use [`GET /perpetual/account/market-fee-rate`](#get-perpetual-account-market-fee-rate). | | `symbols[].max_allowed_leverage` | decimal string | Max allowed leverage (e.g., "100") | | `symbols[].maintenance_margin_rate` | decimal string | Maintenance margin rate (MMR) for this market (e.g., `"0.007"` = 0.7%). Tiered maintenance on positions may still compute `maintenance_margin` from brackets. | | `symbols[].filters` | array | Trading rules (PRICE\_FILTER, LOT\_SIZE, MIN\_NOTIONAL, DEPTH\_MERGE) | **Status Codes**: * `200` - Exchange information retrieved successfully * `500` - Internal server error *** ## Perpetuals Calculation Formulas For frontend display (margin ratio, break-even price, ROI %, etc.), see `perpetuals-frontend-formulas-from-code.md`. Key formulas: * **Cross margin ratio**: `margin_ratio = total_account_equity / total_maintenance_margin` (from `GET /perpetual/account` or `GET /perpetual/accounts`) * **Break-even price**: Long `entry_price - realized_pnl/amount`, Short `entry_price + realized_pnl/amount` (derived, not returned) * **Liquidation price**: Returned by API and WebSocket `position_update` for cross-margin positions *** Historical and current funding rates for perpetual markets. ## Per-market history Retrieve the full funding-rate timeline for a single perpetual symbol. Each entry includes the funding rate, premium index, mark price, and index price at that interval. Supports cursor- or page-based pagination for long histories, with short-lived response caching for high-frequency polling. ## Current-rate snapshot Retrieve the latest funding rate for all active perpetual markets in a single call — useful for dashboards and pre-trade checks. Endpoints, request parameters, and response schemas follow the same conventions as the rest of the Perpetuals Trading API. ## List pagination Perpetual **list** endpoints use opaque **cursor** pagination. Send `use_cursor=true` (optionally with `page_size`). The response returns the first page plus a `next_cursor` token and a `has_more` flag. While `has_more` is `true`, send the previous response's `next_cursor` value as the `cursor` query parameter to fetch the following page. When `has_more` is `false`, `next_cursor` is empty and there are no more pages. **Query parameters** (where noted on each endpoint): | Parameter | Type | Required | Options | Description | | ------------ | ------- | -------- | ----------------- | -------------------------------------------------------------------------------------------- | | `use_cursor` | boolean | No | `true` | Set `true` to use cursor pagination (on the first request) | | `cursor` | string | No | — | Opaque continuation token from the previous response's `next_cursor`. Omit on the first page | | `page_size` | integer | No | see each endpoint | Items per page | **Response fields**: | Field | Type | Description | | ------------- | ------- | --------------------------------------------------------------------- | | `next_cursor` | string | Token to pass as `cursor` for the next page; empty when no more pages | | `has_more` | boolean | Whether another page exists | | `page_size` | integer | Items per page | **Errors**: Malformed `cursor` → `400` with `"error": "invalid_cursor"`. *** ## GET /perpetual/account/market-fee-rate Retrieve the effective maker/taker fee rate for a single market on a perpetuals app session. **Authentication:** Required (read:futures scope) **Query Parameters**: | Parameter | Type | Required | Options | Description | | ---------------- | ------ | -------- | ------- | --------------------------------- | | `app_session_id` | string | Yes | — | Perpetuals account app session ID | | `market` | string | Yes | — | Market symbol (e.g., `BTCUSDT`) | **Response**: ```json theme={null} [ { "app_session_id": "your-session-id", "market": "BTCUSDT", "maker_fee_rate": "0.0002", "taker_fee_rate": "0.0005", "source": "fee_tier", "fee_tier_version": 3 } ] ``` **Response Fields**: The response is a JSON array containing a single object for the requested market: | Field | Type | Description | | ------------------ | -------------- | ------------------------------------------------------- | | `app_session_id` | string | Application session identifier (from request parameter) | | `market` | string | Market symbol | | `maker_fee_rate` | decimal string | Effective maker fee rate | | `taker_fee_rate` | decimal string | Effective taker fee rate | | `source` | string | Origin of the effective fee rate (e.g., `fee_tier`) | | `fee_tier_version` | integer | Version of the fee tier configuration applied | **Status Codes**: * `200` - Account fee rate retrieved successfully * `400` - Missing `app_session_id` or `market` parameter * `401` - Authentication failed *** ## GET /perpetual/accounts Retrieve all perpetuals accounts for the authenticated user. **Authentication:** Required **Response**: ```json theme={null} [ { "id": "550e8400-e29b-41d4-a716-446655440000", "app_session_id": "your-session-id", "owner": "0x1234567890abcdef1234567890abcdef12345678", "state": "active", "opened_at": "2023-12-01T08:00:00.000000Z", "total_account_balance": "10000.00000000", "total_unrealized_pnl": "150.50000000", "total_account_equity": "10150.50000000", "total_allocated_margin": "2000.00000000", "total_locked_balance": "2000.00000000", "total_maintenance_margin": "1000.00000000", "available_balance": "8150.50000000", "transferable_balances": { "USDT": "6400.00000000" }, "initial_leverages": { "BTCYTEST.USD-PERP": "10" }, "balances": [ { "asset_symbol": "USDT", "asset_name": "Tether USD", "total_balance": "10000.00000000", "allocated_balance": "2000.00000000", "locked_balance": "2000.00000000", "available_balance": "8000.00000000", "max_transfer_out": "6400.00000000", "total_balance_usd": "10000.00000000", "allocated_balance_usd": "2000.00000000", "locked_balance_usd": "2000.00000000", "available_balance_usd": "8000.00000000", "last_updated": "2023-12-07T10:30:00.000000Z" } ], "positions": [ { "uuid": "550e8400-e29b-41d4-a716-446655440000", "market": "BTCYTEST.USD-PERP", "direction": "long", "amount": "1.50000000", "entry_price": "35000.00000000", "mark_price": "35100.00000000", "notional_value": "52650.00000000", "leverage": "10.00000000", "unrealized_pnl": "150.00000000", "realized_pnl": "75.00000000", "total_pnl": "225.00000000", "allocated_margin": "5265.00000000", "maintenance_margin": "2632.50000000", "liquidation_price": "31500.00000000", "margin_asset": "USDT", "locked_amount": "0.50000000", "available_amount": "1.00000000" } ] } ] ``` **Response Fields**: | Field | Type | Description | | ---------------------------------- | -------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `id` | string | Unique perpetuals account identifier (UUID) | | `app_session_id` | string | Application session identifier | | `owner` | string | Owner's Ethereum wallet address | | `state` | string | Account state (`active`, `closed`) | | `opened_at` | string | Account creation timestamp | | `total_account_balance` | decimal string | Sum of all collateral balances | | `total_unrealized_pnl` | decimal string | Total unrealized PnL across all positions | | `total_account_equity` | decimal string | Total account equity (balance + unrealized PnL) | | `total_allocated_margin` | decimal string | Total margin allocated to positions (historical name; same numeric value as `total_locked_balance`) | | `total_locked_balance` | decimal string | Sum of locked collateral across all assets (orders + position margin); same value as `total_allocated_margin` | | `total_maintenance_margin` | decimal string | Total maintenance margin required | | `available_balance` | decimal string | (Account-level.) Balance available for new positions or withdrawals. Includes unrealized PnL (total balance − allocated/locked + unrealized PnL). Not the max you can transfer perp→spot; use `transferable_balances` or `balances[].max_transfer_out` for that cap. | | `transferable_balances` | object | (optional) Map of `asset_symbol` → decimal string: max amount the user may transfer perpetuals → spot for that collateral asset (closing-fee reserve; 80% cap when cross-margin positions exist). Omitted when there are no balance rows. | | `balances` | array | Array of collateral balances | | `balances[].asset_symbol` | string | Collateral asset symbol (e.g., "USDT") | | `balances[].asset_name` | string | Display name (when known) | | `balances[].total_balance` | decimal string | Total balance for this asset | | `balances[].allocated_balance` | decimal string | Margin allocated to positions (historical name; same numeric value as `locked_balance`) | | `balances[].locked_balance` | decimal string | Locked collateral for this asset (orders + position margin); same value as `allocated_balance` | | `balances[].available_balance` | decimal string | (Per-asset.) Available for this asset. Includes unrealized PnL (total − locked + unrealized PnL; in single-collateral the PnL is attributed to that asset). | | `balances[].max_transfer_out` | decimal string | Max user perp→spot transfer for this asset (may be lower than `available_balance` when open positions require a closing-fee reserve or cross-margin transfer cap applies). | | `balances[].total_balance_usd` | decimal string | Total balance valued in stablecoin (USD/USDT); `"0"` when no price | | `balances[].allocated_balance_usd` | decimal string | Allocated/locked margin valued in stablecoin; `"0"` when no price | | `balances[].locked_balance_usd` | decimal string | Same as `allocated_balance_usd` (locked collateral in USD terms) | | `balances[].available_balance_usd` | decimal string | Available balance valued in stablecoin; `"0"` when no price | | `balances[].last_updated` | string | Last balance update timestamp | | `initial_leverages` | object | (optional) Map of market → leverage string (e.g. `"10"`). Only present when the account has per-market settings. | | `positions` | array | Array of open positions. May include two rows for the same `market` (one `long`, one `short`), since long and short legs are tracked separately. | | `positions[].uuid` | string | Unique position identifier (always present) | | `positions[].market` | string | Trading market (e.g., "BTCYTEST.USD-PERP") | | `positions[].direction` | string | Position direction (`long` or `short`) | | `positions[].amount` | decimal string | Position size (always positive) | | `positions[].entry_price` | decimal string | Average entry price | | `positions[].mark_price` | decimal string | Current mark price | | `positions[].notional_value` | decimal string | Current notional value (amount x mark\_price) | | `positions[].leverage` | decimal string | Leverage multiplier | | `positions[].unrealized_pnl` | decimal string | Unrealized profit/loss | | `positions[].realized_pnl` | decimal string | Realized profit/loss from this position | | `positions[].total_pnl` | decimal string | Total profit/loss (unrealized + realized) | | `positions[].allocated_margin` | decimal string | Margin allocated to this position | | `positions[].maintenance_margin` | decimal string | Maintenance margin requirement | | `positions[].liquidation_price` | decimal string | Liquidation price (calculated by backend for cross-margin positions) | | `positions[].margin_asset` | string | Collateral asset for margin calculation | | `positions[].locked_amount` | decimal string | Amount currently locked | | `positions[].available_amount` | decimal string | Amount available | **Status Codes**: * `200` - Accounts retrieved successfully * `401` - Authentication failed * `500` - Internal server error *** ## POST /perpetual/account Create a new perpetuals account with a specified app\_session\_id. **Authentication:** Required \> **Account creation completes shortly after this call returns `200`.** The account does not exist immediately; poll `GET /perpetual/account` until it returns a result (typically a few seconds). **Request Body**: ```json theme={null} { "app_session_id": "your-session-id", "owner": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb" } ``` **Request Parameters**: | Parameter | Type | Required | Options | Description | | ---------------- | ------ | -------- | --------------------------- | ---------------------------------------------------------------------------------------- | | `app_session_id` | string | Yes | — | Application session ID for the new perpetual account (typically same as spot account ID) | | `owner` | string | No | default: authenticated user | Owner wallet address | **Response**: ```json theme={null} { "app_session_id": "your-session-id", "owner": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb", "message": "Perpetuals account creation initiated" } ``` **Response Fields**: | Field | Type | Description | | ---------------- | ------ | ----------------------------------------- | | `app_session_id` | string | The app session ID of the created account | | `owner` | string | Owner wallet address | | `message` | string | Status message | **Status Codes**: * `200` - Account creation initiated successfully * `400` - Invalid request parameters (missing app\_session\_id, invalid owner address) * `401` - Authentication failed * `403` - Forbidden (owner mismatch - trying to create account for different wallet) * `500` - Internal server error **Notes**: * The `app_session_id` should typically match the user's spot account ID to allow seamless transfers * The account becomes available shortly after this request completes * Attempting to create an account with an existing `app_session_id` will return an error *** ## GET /perpetual/account Retrieve detailed information for a specific perpetuals account including all balances, positions, and account-level metrics. **Authentication:** Required **Query Parameters**: | Parameter | Type | Required | Options | Description | | ---------------- | ------ | -------- | ------- | --------------------------------- | | `app_session_id` | string | Yes | — | Perpetuals account app session ID | **Request**: ```http theme={null} GET /perpetual/account?app_session_id=your-session-id ``` **Response**: ```json theme={null} { "id": "550e8400-e29b-41d4-a716-446655440000", "app_session_id": "your-session-id", "owner": "0x1234567890abcdef1234567890abcdef12345678", "state": "active", "opened_at": "2023-12-01T08:00:00.000000Z", "total_account_balance": "10000.00000000", "total_unrealized_pnl": "150.50000000", "total_account_equity": "10150.50000000", "total_allocated_margin": "2000.00000000", "total_locked_balance": "2000.00000000", "total_maintenance_margin": "1000.00000000", "available_balance": "8150.50000000", "transferable_balances": { "USDT": "6400.00000000" }, "initial_leverages": { "BTCYTEST.USD-PERP": "10" }, "balances": [ { "asset_symbol": "USDT", "asset_name": "Tether USD", "total_balance": "10000.00000000", "allocated_balance": "2000.00000000", "locked_balance": "2000.00000000", "available_balance": "8000.00000000", "max_transfer_out": "6400.00000000", "total_balance_usd": "10000.00000000", "allocated_balance_usd": "2000.00000000", "locked_balance_usd": "2000.00000000", "available_balance_usd": "8000.00000000", "last_updated": "2023-12-07T10:30:00.000000Z" } ], "positions": [] } ``` **Response Fields**: Same as `/perpetual/accounts` response (single account object), including optional `initial_leverages` and `transferable_balances`. **Note on `available_balance` vs transfers**: The name appears in two places—(1) at the **account root**: aggregate balance available for new positions; (2) inside each `balances[]` element: available for that asset. **Both include unrealized PnL** (formula: total − allocated/locked + unrealized PnL). For **perp→spot transfer** limits, use `transferable_balances` (account root) or `balances[].max_transfer_out` per asset—these match WebSocket `perpetuals_account.account_update` and account for closing-fee reserve and cross-margin transfer caps. **Status Codes**: * `200` - Account retrieved successfully * `400` - Missing app\_session\_id parameter * `401` - Authentication failed * `404` - Account not found * `500` - Internal server error *** ## POST /perpetual/warning/mute Mute this perpetuals account's liquidation warnings for 24 hours. **Authentication:** Required (trade:futures scope) **Request Body**: ```json theme={null} { "app_session_id": "your-session-id" } ``` **Request Fields**: | Parameter | Type | Required | Options | Description | | ---------------- | ------ | -------- | ------- | --------------------------------- | | `app_session_id` | string | Yes | — | Perpetuals account app session ID | **Response** (200): ```json theme={null} { "app_session_id": "your-session-id", "muted_until": "2026-06-11T10:30:00Z" } ``` **Response Fields**: | Field | Type | Description | | ---------------- | ------ | ---------------------------------------------------------------- | | `app_session_id` | string | Application session identifier (from request body) | | `muted_until` | string | RFC3339 UTC timestamp until which liquidation warnings are muted | **Status Codes**: * `200` - Liquidation warnings muted successfully * `400` - Invalid request body or missing `app_session_id` * `401` - Authentication failed * `404` - Account not found * `500` - Internal server error * `503` - Service temporarily unavailable *** ## GET /perpetual/balance Retrieve collateral balances for a specific perpetuals account. **Authentication:** Required **Query Parameters**: | Parameter | Type | Required | Options | Description | | ---------------- | ------ | -------- | ------- | --------------------------------- | | `app_session_id` | string | Yes | — | Perpetuals account app session ID | **Request**: ```http theme={null} GET /perpetual/balance?app_session_id=your-session-id ``` **Response**: ```json theme={null} [ { "asset_symbol": "USDT", "asset_name": "Tether USD", "total_balance": "10000.00000000", "allocated_balance": "2000.00000000", "locked_balance": "2000.00000000", "available_balance": "8000.00000000", "max_transfer_out": "6400.00000000", "total_balance_usd": "10000.00000000", "allocated_balance_usd": "2000.00000000", "locked_balance_usd": "2000.00000000", "available_balance_usd": "8000.00000000", "last_updated": "2023-12-07T10:30:00.000000Z" }, { "asset_symbol": "USDC", "asset_name": "USD Coin", "total_balance": "5000.00000000", "allocated_balance": "1000.00000000", "locked_balance": "1000.00000000", "available_balance": "4000.00000000", "max_transfer_out": "4000.00000000", "total_balance_usd": "5000.00000000", "allocated_balance_usd": "1000.00000000", "locked_balance_usd": "1000.00000000", "available_balance_usd": "4000.00000000", "last_updated": "2023-12-07T10:30:00.000000Z" } ] ``` **Response Fields**: | Field | Type | Description | | ----------------------- | -------------- | --------------------------------------------------------------------------------------------------------------- | | `asset_symbol` | string | Collateral asset symbol | | `asset_name` | string | Display name (when known) | | `total_balance` | decimal string | Total balance for this asset | | `allocated_balance` | decimal string | Margin allocated to positions (historical name; same numeric value as `locked_balance`) | | `locked_balance` | decimal string | Locked collateral for this asset (orders + position margin); same value as `allocated_balance` | | `available_balance` | decimal string | Balance available for new positions (includes unrealized PnL share for this asset) | | `max_transfer_out` | decimal string | Max user perp→spot transfer for this asset (same as `transferable_balances[asset]` on `GET /perpetual/account`) | | `total_balance_usd` | decimal string | Total balance valued in stablecoin (USD/USDT); `"0"` when no price | | `allocated_balance_usd` | decimal string | Allocated/locked margin valued in stablecoin; `"0"` when no price | | `locked_balance_usd` | decimal string | Same as `allocated_balance_usd` (locked collateral in USD terms) | | `available_balance_usd` | decimal string | Available balance valued in stablecoin; `"0"` when no price | | `last_updated` | string | Last balance update timestamp | **Status Codes**: * `200` - Balances retrieved successfully * `400` - Missing app\_session\_id parameter * `401` - Authentication failed * `404` - Account not found * `500` - Internal server error *** ## GET /perpetual/transfer-assets Retrieve the **system-level** perpetual transfer asset configuration. This endpoint returns which assets are configured for spot/perps transfer at the platform level.\ Only assets that are both **active** and marked as **stablecoin** are returned.\ It does **not** represent user-level transferability (e.g., user balance availability). **Authentication:** Not required (public endpoint) **Request**: ```http theme={null} GET /perpetual/transfer-assets ``` **Response**: ```json theme={null} [ { "symbol": "USDT", "name": "Tether USD", "decimals": 6, "is_active": true } ] ``` **Response Fields**: | Field | Type | Description | | ----------- | ------- | ------------------------------------------------------------------ | | `symbol` | string | Asset symbol | | `name` | string | Display name | | `decimals` | integer | Decimal precision for min transfer amount logic (`10^(-decimals)`) | | `is_active` | boolean | Whether this asset is currently enabled for transfer | Only assets that are both active and stablecoin are included (stablecoin flag is not repeated in the JSON). **Status Codes**: * `200` - Transfer assets retrieved successfully * `500` - Internal server error *** ## GET /perpetual/transaction/history Retrieve unified perpetual transaction history for a wallet + app session. This endpoint aggregates balance-changing events (funding payments, internal transfers, fees, realized PnL, liquidations, ADL, etc.) into a single paginated history from the **user's perspective**. Each row is one `(transaction_id, asset)` pair: * Positive `amount` → balance increase * Negative `amount` → balance decrease **Authentication:** Required **Query Parameters**: | Parameter | Type | Required | Options | Description | | ---------------- | ------- | -------- | ---------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- | | `app_session_id` | string | Yes | — | Perpetuals account app session ID | | `type` | string | No | `""`, `funding_fee`, `transfer`, `fee`, `realized_pnl`, `liquidation`, `adl` | High-level transaction type filter (see mapping below) | | `market` | string | No | — | Market filter (e.g. `BTC-USDT-PERP`) | | `asset` | string | No | — | Asset symbol to filter by (e.g. margin asset symbol) | | `start_time` | integer | No | Unix timestamp in seconds (UTC) | Inclusive range start. See Time range below. | | `end_time` | integer | No | Unix timestamp in seconds (UTC) | Inclusive range end. See Time range below. | | `use_cursor` | boolean | No | — | Set `true` to use cursor pagination (first request). See [List pagination](#list-pagination). | | `cursor` | string | No | — | Opaque continuation token from the previous response's `next_cursor`. Omit on the first page. | | `page_size` | integer | No | default `50`, max `100` | Number of items per page | `type` filter mapping: * `""` (empty / omitted): User-facing types only (excludes internal order bookkeeping such as `ORDER_*`, `DEPOSIT`, `WITHDRAWAL`, etc.) * `"funding_fee"`: Funding payments (maps to `FUNDING_FEE_IN`, `FUNDING_FEE_OUT`) * `"transfer"`: Internal asset transfers (maps to `TRANSFER_IN`, `TRANSFER_OUT`) * `"fee"`: Trading fee-related events (maps to `FEE`, `FEE_WAIVER_DISTRESSED_CLOSE`, `POSITION_OPEN_FEE`, `POSITION_CLOSE_FEE`) * `"realized_pnl"`: Realized PnL events (maps to `REALIZED_PNL`) * `"liquidation"`: Liquidation events (maps to `LIQUIDATION`, `LIQUIDATION_COMPLETE`) * `"adl"`: ADL events (maps to `ADL_COUNTERPARTY_CLOSE`, `ADL_TAKEN_OVER_CLOSE`) * Compatibility note: ADL events are intentionally separated from the `liquidation` filter; clients that want all forced-deleveraging events should query both `type=liquidation` and `type=adl`. **Time range**: `start_time` and `end_time` are applied unchanged. When bounds are omitted (or sent as `0`), the backend applies a default window of the **last 30 days** ending at now (UTC): | Client sends | Effective window | | ----------------------------------- | ----------------------------------------------------------------------------------------- | | Neither `start_time` nor `end_time` | `[now − 30d, now]` | | `start_time` only | `[start_time, now]` | | `end_time` only | `[end_time − 30d, end_time]` | | Both | `[start_time, end_time]` (if `start_time > end_time`, start is reset to `end_time − 30d`) | The time window is applied on the transaction time of each event. **Request** (explicit time range): ```http theme={null} GET /perpetual/transaction/history?app_session_id=your-session-id&type=funding_fee&market=BTC-USDT-PERP&asset=USDT&start_time=1704067200&end_time=1704153600&page_size=20 ``` **Request** (default last 30 days — omit `start_time` and `end_time`; cursor first page): ```http theme={null} GET /perpetual/transaction/history?app_session_id=your-session-id&use_cursor=true&page_size=20 ``` **Request** (cursor page 2): ```http theme={null} GET /perpetual/transaction/history?app_session_id=your-session-id&use_cursor=true&cursor=1701943800000:5721092:USDT&page_size=20 ``` **Response**: ```json theme={null} { "items": [ { "transaction_id": 12345, "transaction_time": "2023-12-07T10:00:00.000000Z", "transaction_type": "FUNDING_FEE_IN", "market": "BTC-USDT-PERP", "asset": "USDT", "amount": "12.34567890" }, { "transaction_id": 12344, "transaction_time": "2023-12-07T09:45:00.000000Z", "transaction_type": "TRANSFER_OUT", "market": "", "asset": "USDT", "amount": "-100.00000000" } ], "has_more": false, "next_cursor": "", "page_size": 20 } ``` **Pagination**: Cursor only. Send `use_cursor=true` on the first request, then follow `next_cursor` while `has_more` is `true` (see [List pagination](#list-pagination)). Malformed `cursor` → `400` / `"error": "invalid_cursor"`. **Response Fields**: | Field | Type | Description | | -------------------------- | -------------- | ----------------------------------------------------------------------------------------------------------------------------------- | | `items` | array | Array of transaction history records | | `items[].transaction_id` | integer | Internal transaction identifier | | `items[].transaction_time` | string | Transaction timestamp in RFC3339 format | | `items[].transaction_type` | string | Low-level transaction type (e.g., `FUNDING_FEE_IN`, `TRANSFER_OUT`, `FEE`, `REALIZED_PNL`, `LIQUIDATION`, `ADL_COUNTERPARTY_CLOSE`) | | `items[].market` | string | Related market symbol when applicable; empty string for non-market-specific events (e.g. some transfers) | | `items[].asset` | string | Asset symbol impacted by the transaction | | `items[].amount` | decimal string | Signed amount from the user's perspective (positive = balance increase, negative = balance decrease) | | `has_more` | boolean | Whether another page exists | | `next_cursor` | string | Opaque next-page token (empty when no more pages) | | `page_size` | integer | Number of items requested per page | **Status Codes**: * `200` - Transaction history retrieved successfully * `400` - Invalid query parameters (including malformed `cursor`) (e.g., missing `app_session_id`, invalid `type`, malformed `cursor`) * `401` - Authentication failed * `500` - Internal server error *** ## GET /perpetual/positions Retrieve all open positions for a specific perpetuals account. **Position mode**: Each row’s `direction` is `long` or `short` (stored leg). A market may return two rows (one `long`, one `short`), since long and short legs are tracked separately. **Authentication:** Required **Query Parameters**: | Parameter | Type | Required | Options | Description | | ---------------- | ------ | -------- | ------- | --------------------------------- | | `app_session_id` | string | Yes | — | Perpetuals account app session ID | **Request**: ```http theme={null} GET /perpetual/positions?app_session_id=your-session-id ``` **Response**: ```json theme={null} [ { "uuid": "550e8400-e29b-41d4-a716-446655440000", "market": "BTCYTEST.USD-PERP", "direction": "long", "amount": "1.50000000", "entry_price": "35000.00000000", "mark_price": "35100.00000000", "notional_value": "52650.00000000", "leverage": "10.00000000", "unrealized_pnl": "150.00000000", "realized_pnl": "75.00000000", "total_pnl": "225.00000000", "allocated_margin": "5265.00000000", "maintenance_margin": "2632.50000000", "liquidation_price": "31500.00000000", "margin_asset": "USDT", "margin_mode": "cross", "locked_amount": "0.50000000", "available_amount": "1.00000000" } ] ``` **Response Fields**: | Field | Type | Description | | -------------------- | -------------- | -------------------------------------------------------------------- | | `uuid` | string | Unique position identifier (always present) | | `market` | string | Trading market (e.g., "BTCYTEST.USD-PERP") | | `direction` | string | Position direction (`long` or `short`) | | `amount` | decimal string | Position size (always positive) | | `entry_price` | decimal string | Average entry price | | `mark_price` | decimal string | Current mark price used for PnL calculation | | `notional_value` | decimal string | Current notional value (amount x mark\_price) | | `leverage` | decimal string | Leverage multiplier | | `unrealized_pnl` | decimal string | Current unrealized profit/loss | | `realized_pnl` | decimal string | Realized profit/loss from partial closes | | `total_pnl` | decimal string | Total profit/loss (unrealized + realized) | | `allocated_margin` | decimal string | Margin allocated to this position | | `maintenance_margin` | decimal string | Maintenance margin requirement | | `liquidation_price` | decimal string | Liquidation price (calculated by backend for cross-margin positions) | | `margin_asset` | string | Collateral asset (e.g., "USDT") | | `margin_mode` | string | Margin mode (always `cross`) | | `locked_amount` | decimal string | Amount currently locked | | `available_amount` | decimal string | Amount available | **Status Codes**: * `200` - Positions retrieved successfully * `400` - Missing app\_session\_id parameter * `401` - Authentication failed * `404` - Account not found * `500` - Internal server error *** ## POST /perpetual/positions/close Batch-submit **market IOC** close orders for every open position leg on the account that has **available** size greater than zero. Each leg uses the same path as `POST /perpetual/order`. * If `market` is omitted or empty: all matching legs across markets are closed. * If `market` is set: only positions for that market (case-insensitive match; symbol is normalized to uppercase for validation against exchange info). * Legs are processed with bounded parallelism (worker pool) for lower latency. * Safety cap: at most **50** closable legs are submitted per request; when more legs exist, the response includes `remaining_count` and `partial=true`. **Position mode**: Each closable leg uses `direction` `long` or `short` with `reduce_only: true`. A market may have separate long and short legs, which are closed independently. **Authentication:** Required (trade scope). Ownership of `app_session_id` is verified. **Request Body**: ```json theme={null} { "app_session_id": "your-session-id", "market": "BTCYTEST.USD-PERP" } ``` **Request Fields**: | Parameter | Type | Required | Options | Description | | ---------------- | ------ | -------- | ------- | --------------------------------------------------------------------------------------------------------------------------------- | | `app_session_id` | string | Yes | — | Perpetuals account app session ID | | `market` | string | No | — | When present, only this market's positions are closed; must exist in perpetuals exchange info when the market cache is configured | **Response** (200): ```json theme={null} { "message": "dispatched 2 close order(s)", "positions_submitted": 2, "failed_count": 0, "remaining_count": 0, "partial": false, "orders": [ { "market": "BTCYTEST.USD-PERP", "direction": "long", "margin_mode": "cross", "order_uuid": "550e8400-e29b-41d4-a716-446655440000" } ], "failed": [] } ``` **Response Fields**: | Field | Type | Description | | ---------------------- | ------- | -------------------------------------------------------------------------- | | `message` | string | Summary for the client | | `positions_submitted` | integer | Number of close orders successfully dispatched | | `failed_count` | integer | Number of legs that failed validation or submission (see `failed`) | | `remaining_count` | integer | Number of additional closable legs not processed due to per-request cap | | `partial` | boolean | `true` when `remaining_count > 0` (caller should invoke again to continue) | | `orders` | array | Successful items | | `orders[].market` | string | Market of the submitted close order (from the position row) | | `orders[].direction` | string | Position direction (`long` or `short`) | | `orders[].margin_mode` | string | Margin mode (always `cross`) | | `orders[].order_uuid` | string | UUID of the submitted order | | `failed` | array | Per-leg failures | | `failed[].market` | string | Market of the failed leg | | `failed[].direction` | string | (optional) Position direction (`long` or `short`) | | `failed[].margin_mode` | string | (optional) Margin mode (always `cross`) | | `failed[].error` | string | Failure description | | `failed[].error_code` | string | (optional) Client-visible error code, same idea as `POST /perpetual/order` | When there are no closable legs (all `available_amount` is zero), the endpoint returns `200` with `positions_submitted: 0` and an explanatory `message`. **Status Codes**: * `200` - Request completed (check `failed` for partial failures) * `400` - Invalid JSON, missing `app_session_id`, or unknown `market` (when provided and exchange info is available) * `401` - Authentication failed * `403` - Permission denied for `(wallet_address, app_session_id)` * `404` - Perpetual account not found * `502` - Backend request failed * `503` - Service temporarily unavailable *** ## POST /perpetual/leverage Sets **initial leverage** per account and market. **Order creation does not accept leverage**; it is resolved from stored settings when matching orders. Use this endpoint (or the default, typically `10`) before trading if you need a specific multiplier. **How to read current leverage**: `GET /perpetual/accounts` returns `initial_leverages` (market → leverage string). Positions and orders also expose an effective `leverage` field. **Restrictions & behavior**: * **Open orders**: Changing leverage is **rejected** while **any open order** exists for that **market** (`error` e.g. `order_exists`). Cancel or fill those orders first. * **Open positions**: Changing leverage is **allowed**. The new leverage is applied atomically: position `allocated_margin` is recalculated from notional ÷ leverage, and locked balance is adjusted. The call may still **fail** if the account does not have enough free collateral for a higher required margin, or if the new margin would fall **below maintenance** for a position (`set_leverage_failed` or a similar message). * **Validation**: `leverage >= 1` is required, and `leverage <= max_allowed_leverage` for that market (`leverage_exceeds_max`). **Authentication:** Required (JWT or API Key). The wallet address must be present in the auth context; ownership of `app_session_id` is verified. **Request Body**: ```json theme={null} { "app_session_id": "your-session-id", "market": "BTCYTEST.USD-PERP", "leverage": "20" } ``` **Request Fields**: | Parameter | Type | Required | Options | Description | | ---------------- | ---------------- | -------- | --------------------------------------------------- | ------------------------------------------------------------------------------- | | `app_session_id` | string | Yes | — | Perpetuals account app session ID | | `market` | string | Yes | — | Market symbol (e.g., `BTCYTEST.USD-PERP`). Trimmed and uppercased by the server | | `leverage` | number or string | Yes | `>= 1` and `<= max_allowed_leverage` for the market | Leverage multiplier (e.g., `20` or `"20"`) | **Response** (200): ```json theme={null} { "success": true, "message": "leverage updated successfully", "market": "BTCYTEST.USD-PERP", "leverage": "20" } ``` **Response Fields**: | Field | Type | Description | | ---------- | -------------- | ---------------------------------------- | | `success` | boolean | Whether the operation succeeded | | `message` | string | Human-readable message | | `market` | string | Market symbol for which leverage was set | | `leverage` | decimal string | Confirmed leverage | **Error responses** (non-exhaustive; `success` is `false` when HTTP status is not 200): | HTTP | `error` (when present) | Meaning | | ----- | ---------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------- | | `400` | `invalid_request_format` | Malformed JSON | | `400` | `missing_app_session_id` | `app_session_id` empty | | `400` | `missing_market` | `market` empty | | `400` | `invalid_leverage_value` | Leverage `< 1` | | `400` | `no_permitted` | Account not found or not accessible for this wallet | | `400` | `leverage_exceeds_max`, `order_exists`, `insufficient_balance`, `leverage_exceeds_safe_margin`, `account_not_active`, `set_leverage_failed`, … | See `message` for detail. | | `401` | `missing_wallet_address` | Authenticated context has no wallet | | `503` | `service_unavailable` | Service temporarily unavailable for this user | | `500` | `internal_error` | Internal server error | **Error body** (400 from business rules): ```json theme={null} { "success": false, "error": "insufficient_balance", "message": "insufficient balance: insufficient available balance to apply new leverage (required extra margin: ..., available: ...)" } ``` **Status Codes**: * `200` - Leverage set successfully * `400` - Validation or business rule failure (see table) * `401` - Not authenticated or missing wallet in context * `503` - Service temporarily unavailable * `500` - Internal server error *** ## GET /perpetual/position-history Retrieve closed position history with pagination. Only returns positions that have been fully closed. Default ordering matches `sort_by=closed_at` and `sort_dir=desc` with a stable secondary sort on internal row id. **Authentication:** Required **Query Parameters**: | Parameter | Type | Required | Options | Description | | ---------------- | ------- | -------- | ---------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ | | `app_session_id` | string | Yes | — | Perpetuals account app session ID | | `market` | string | No | — | Exact market symbol filter; normalized to uppercase before lookup (e.g. `btcytest.usd-perp` matches `BTCYTEST.USD-PERP`) | | `opened_from` | string | No | RFC3339 or RFC3339Nano | Inclusive lower bound on `opened_at` | | `opened_to` | string | No | RFC3339 or RFC3339Nano | Inclusive upper bound on `opened_at` | | `closed_from` | string | No | RFC3339 or RFC3339Nano | Inclusive lower bound on `closed_at` | | `closed_to` | string | No | RFC3339 or RFC3339Nano | Inclusive upper bound on `closed_at` | | `sort_by` | string | No | `opened_at`, `closed_at` (default `closed_at`) | Sort field; other values → `400` | | `sort_dir` | string | No | `asc`, `desc` (default `desc`) | Sort direction; other values → `400` | | `use_cursor` | boolean | No | — | Set `true` to use cursor pagination (first request). See [List pagination](#list-pagination). | | `cursor` | string | No | — | Opaque continuation token from the previous response's `next_cursor`. Omit on the first page. | | `page_size` | integer | No | `1`–`100` (default `50`) | Number of positions per page; out-of-range when supplied → `400` | **Request**: ```http theme={null} GET /perpetual/position-history?app_session_id=your-session-id&market=BTCYTEST.USD-PERP&opened_from=2024-01-01T00:00:00Z&closed_to=2024-01-31T23:59:59Z&sort_by=closed_at&sort_dir=desc&use_cursor=true&page_size=20 ``` **Response**: ```json theme={null} { "positions": [ { "id": "550e8400-e29b-41d4-a716-446655440000", "perps_account_id": "550e8400-e29b-41d4-a716-446655440001", "market": "BTCYTEST.USD-PERP", "direction": "long", "amount": "1.50000000", "entry_price": "35000.00000000", "leverage": "10.00000000", "allocated_margin": "5250.00000000", "realized_pnl": "225.50000000", "close_reason": "normal", "exit_price": "35150.00000000", "closed_quantity": "1.50000000", "max_held": "2.00000000", "initial_margin": "5000.00000000", "total_trading_fee": "12.50000000", "net_funding_fee": "-1.25000000", "liquidation_price": "0", "margin_mode": "cross", "pnl_ratio": "4.51000000", "opened_at": "2023-12-07T10:00:00.000000Z", "updated_at": "2023-12-07T11:30:00.000000Z", "closed_at": "2023-12-07T11:30:00.000000Z" } ], "page_size": 20, "next_cursor": "1701943800000:550e8400-e29b-41d4-a716-446655440000", "has_more": true } ``` **Pagination**: Cursor only (see [List pagination](#list-pagination)). Malformed `cursor` → `400` / `invalid_cursor`. **Response Fields**: | Field | Type | Description | | ------------------------------- | -------------- | ------------------------------------------------------------------------------------------------------------ | | `positions` | array | Array of closed position objects | | `positions[].id` | string | Position ID (UUID) | | `positions[].perps_account_id` | string | Perpetuals account ID (UUID) | | `positions[].market` | string | Trading market | | `positions[].direction` | string | Position direction (`long` or `short`) | | `positions[].amount` | decimal string | Position size (amount) | | `positions[].entry_price` | decimal string | Average entry price | | `positions[].leverage` | decimal string | Leverage multiplier used | | `positions[].allocated_margin` | decimal string | Margin that was allocated | | `positions[].realized_pnl` | decimal string | Final realized profit/loss | | `positions[].close_reason` | string | Close reason (`normal`, `liquidated`, `adl`) | | `positions[].exit_price` | decimal string | Weighted-average close price over all close fills | | `positions[].closed_quantity` | decimal string | Total quantity closed for the position lifecycle | | `positions[].max_held` | decimal string | Peak absolute held quantity during the position lifecycle | | `positions[].initial_margin` | decimal string | Margin at first open (used for ROI) | | `positions[].total_trading_fee` | decimal string | Sum of linked trade fees for this position lifecycle | | `positions[].net_funding_fee` | decimal string | Signed cumulative funding for this position lifecycle (positive = received by user, negative = paid by user) | | `positions[].liquidation_price` | decimal string | Liquidation trigger snapshot for liquidated positions (else zero/empty) | | `positions[].margin_mode` | string | Margin mode (always `cross`) | | `positions[].pnl_ratio` | decimal string | Realized ROE% = `realized_pnl / initial_margin * 100` | | `positions[].opened_at` | string | Position open timestamp | | `positions[].updated_at` | string | Last update timestamp | | `positions[].closed_at` | string | Position close timestamp | | `next_cursor` | string | Opaque next-page token (empty when no more pages) | | `has_more` | boolean | Whether another page exists | | `page_size` | integer | Number of positions per page | Note: for legacy closed positions created before these fields were persisted, `max_held` and `initial_margin` can be `0`, which means historical values are unavailable rather than actual zero exposure.\ Note: for positions that were already open when max-held/initial-margin persistence was introduced, `initial_margin` reflects migration-time/live-update value rather than the original open-time margin. **Status Codes**: * `200` - Position history retrieved successfully * `400` - Invalid query parameters (including malformed `cursor`) (e.g. unparsable time strings, `opened_from` after `opened_to`, `closed_from` after `closed_to`, invalid `sort_by` / `sort_dir`, or `page_size` out of **1–100** when supplied) * `401` - Authentication failed or missing wallet in context * `403` - Permission denied (authenticated wallet is not the owner of `app_session_id`) * `404` - Account not found * `500` - Internal server error *** ## GET /perpetual/position-history/ Retrieve **fill-level** history for a **single closed** position (one UUID from `GET /perpetual/position-history`). Results are **cursor-paginated** over the underlying trade fills for that position (chronological order). Summary fields for the position itself are available on the list endpoint item with the same `id`. **Authentication:** Required (JWT or API Key, `read:futures` scope). Owner is the authenticated wallet; must match the perpetuals account for `app_session_id`. **Path Parameters**: | Parameter | Type | Required | Options | Description | | --------- | ------ | -------- | ------- | -------------------- | | `id` | string | Yes | — | Closed position UUID | **Query Parameters**: | Parameter | Type | Required | Options | Description | | ---------------- | ------- | -------- | -------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `app_session_id` | string | Yes | — | Perpetuals account app session ID | | `page_size` | integer | No | positive integer, default `200`, values above `500` clamped to `500` | Number of underlying trades loaded per request | | `cursor` | string | No | `RFC3339Nano\|uint64` (pipe-separated) | Opaque pagination cursor from the previous response's `next_cursor`. Omit on the first page. Malformed values typically surface as `500` from the backend rather than `400`. | **Pagination** (`cursor` / `next_cursor`): * The server advances in **trade execution order** (`executed_at` ascending, then stable `id` tie-break). * `next_cursor` is a tuple string: `|` (UTC in the timestamp part). Pass it back as `cursor` to fetch the next window. * `has_more` is `true` when more trades exist after this page; when `false`, `next_cursor` is typically empty. **Request** (first page): ```http theme={null} GET /perpetual/position-history/550e8400-e29b-41d4-a716-446655440000?app_session_id=your-session-id&page_size=50 ``` **Request** (next page): ```http theme={null} GET /perpetual/position-history/550e8400-e29b-41d4-a716-446655440000?app_session_id=your-session-id&page_size=50&cursor=2023-12-07T10%3A05%3A10.000000000Z%7C12345 ``` **Response**: ```json theme={null} { "fills": [ { "id": "6c611f2f-8bf9-4d53-8dc0-bb8ce31ec6ff", "direction": "long", "amount": "1.00000000", "price": "34900.00000000", "pnl": "0", "fee": "4.20000000", "fee_currency": "USD", "exec_type": "trade", "kind": "open", "executed_at": "2023-12-07T10:05:10.000000Z" }, { "id": "f9733de9-ec8d-4274-96f8-ec57d6fb986f", "direction": "long", "amount": "1.00000000", "price": "35200.00000000", "pnl": "300.00000000", "fee": "5.10000000", "fee_currency": "USD", "exec_type": "liquidation", "kind": "close", "executed_at": "2023-12-07T11:29:59.000000Z" } ], "next_cursor": "2023-12-07T11:29:59.000000000Z|67890", "has_more": false } ``` **Response Fields**: | Field | Type | Description | | ---------------------- | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | | `fills` | array | Per-fill rows derived from trades in the current window (open and close perspectives are combined in one list; each row's `kind` is `open` or `close`) | | `fills[].id` | string | Trade UUID | | `fills[].direction` | string | Position leg direction (`long` or `short`) | | `fills[].amount` | decimal string | Fill amount | | `fills[].price` | decimal string | Fill price | | `fills[].pnl` | decimal string | Fill realized PnL (`0` for `open` fills) | | `fills[].fee` | decimal string | Fee paid for that fill from this account perspective | | `fills[].fee_currency` | string | Fee currency | | `fills[].exec_type` | string | Execution source (`trade`, `liquidation`, `liquidation_takeover`, `adl`) | | `fills[].kind` | string | Fill role (`open` or `close`) | | `fills[].executed_at` | string | Fill execution timestamp (RFC3339 / RFC3339Nano) | | `next_cursor` | string | Cursor for the next request (empty when there is no next page) | | `has_more` | boolean | Whether more trades exist after this page | **Status Codes**: * `200` - Position history detail retrieved successfully * `400` - Missing `app_session_id`, missing path `id`, invalid `page_size` (non-positive when supplied), or invalid position UUID * `401` - Authentication failed or missing wallet in context * `403` - Permission denied (wallet not owner of `app_session_id`, or position belongs to another account) * `404` - Position not found (or no history payload) * `409` - Position is not closed (`failed_precondition` — open positions have no fill history on this route) * `500` - Internal server error (including malformed `cursor` in some deployments) *** ## POST /perpetual/order Create a new perpetuals order. **Authentication:** Required **Request Body** (`direction` is `long` or `short`): ```json theme={null} { "app_session_id": "your-session-id", "market": "BTCYTEST.USD-PERP", "side": "buy", "direction": "long", "type": "limit", "amount": "0.5", "price": "35000", "leverage": "10", "time_in_force": "gtc", "reduce_only": false } ``` \> **Position legs**: Long and short legs are tracked separately. Set `direction` to the leg you are trading and use `reduce_only` to close. **Request Parameters**: | Parameter | Type | Required | Options | Description | | ----------------- | ------- | -------- | ------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------ | | `app_session_id` | string | Yes | — | Perpetuals account app session ID | | `market` | string | Yes | — | Trading market (e.g., "BTCYTEST.USD-PERP") | | `side` | string | Yes | `buy`, `sell` | Order side | | `direction` | string | Yes | `long`, `short` | Position leg direction | | `type` | string | Yes | `limit`, `market`, `trigger_limit`, `trigger_market` | Order type | | `amount` | string | Yes | — | Order amount in base asset (decimal format) | | `price` | string | No | required for `limit` orders | Limit price | | `leverage` | string | Yes | — | Sent with the request; effective margin rules still follow account/market settings from `POST /perpetual/leverage` | | `time_in_force` | string | No | `gtc`, `ioc`, `fok` (default `gtc` for `limit` orders) | Time in force — Good-Till-Cancelled, Immediate-Or-Cancel, Fill-Or-Kill | | `reduce_only` | boolean | No | default `false` | If true, order can only reduce/close an existing position | | `client_order_id` | string | No | — | Client-supplied order id | | `trigger_price` | string | No | — | For trigger / stop / take-profit style orders (see OpenAPI) | | `trigger_type` | string | No | — | For trigger / stop / take-profit style orders (see OpenAPI) | **Leverage**: Also configured via `POST /perpetual/leverage` before the first order. Inspect `GET /perpetual/accounts` (`initial_leverages`) for current settings. \> **Margin mode**: All perpetual positions use cross margin. Passing `margin_mode` in the order request is not accepted. **Response**: ```json theme={null} { "order_uuid": "550e8400-e29b-41d4-a716-446655440000" } ``` **Response Fields**: | Field | Type | Description | | ------------ | ------ | ------------------------- | | `order_uuid` | string | UUID of the created order | **Status Codes**: * `200` - Order created successfully * `400` - Invalid request parameters, validation failed, or the order was rejected (e.g. insufficient margin) * `401` - Authentication failed * `500` - Internal server error **Error response** (typical for `400` — validation or rejection, same family as other trading routes): ```json theme={null} { "error": "insufficient_margin", "message": "insufficient margin. Available:9.62, Required:9.6256" } ``` * `error`: Machine-readable code (`snake_case`), e.g. `insufficient_margin`, `lock_funds_rejected`, `validation_failed`. * `message`: Human-readable detail. *** ## DELETE /perpetual/order Cancel an existing perpetuals order. \> **Known Issue**: The API returns `200` with success message, but the order may remain in `wait` state. Cancel functionality is not reliably working. **Authentication:** Required **Request Body**: ```json theme={null} { "app_session_id": "your-session-id", "market": "BTCYTEST.USD-PERP", "order_uuid": "550e8400-e29b-41d4-a716-446655440000" } ``` **Request Parameters**: | Parameter | Type | Required | Options | Description | | ---------------- | ------ | -------- | ------- | --------------------------------- | | `app_session_id` | string | Yes | — | Perpetuals account app session ID | | `market` | string | Yes | — | Trading market | | `order_uuid` | string | Yes | — | UUID of the order to cancel | **Response**: ```json theme={null} { "message": "Order cancellation request sent successfully" } ``` **Status Codes**: * `200` - Cancellation request sent successfully * `400` - Invalid request or missing parameters * `401` - Authentication failed * `500` - Internal server error *** ## DELETE /perpetual/orders Cancel **all open** perpetuals orders for an account, optionally limited to one market. **Authentication:** Required **Request Body**: ```json theme={null} { "app_session_id": "your-session-id", "market": "BTCYTEST.USD-PERP" } ``` **Request Fields**: | Parameter | Type | Required | Options | Description | | ---------------- | ------ | -------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------- | | `app_session_id` | string | Yes | — | Perpetuals account app session ID | | `market` | string | No | — | When empty or omitted, open orders in all markets are targeted; when set, only orders for that exact market string (as stored on open orders) | **Behavior**: The server lists open orders, then dispatches a cancellation for each one. Trigger orders in `trigger_wait` / `trigger_triggered` are also cancelled (same pattern as `DELETE /perpetual/order`). **Response** (200): ```json theme={null} { "message": "Successfully dispatched 3 order cancellations", "total_orders": 3, "canceled_count": 3, "failed_count": 0 } ``` When there are no open orders: ```json theme={null} { "message": "No open orders to cancel", "canceled_count": 0 } ``` **Response Fields**: | Field | Type | Description | | ---------------- | ------- | --------------------------------------------------------------------------------------------------- | | `message` | string | Summary | | `total_orders` | integer | Open orders found in the listing pass (omitted when count is zero in the "no open orders" response) | | `canceled_count` | integer | Cancel requests successfully dispatched | | `failed_count` | integer | Cancel requests that failed to dispatch | **Status Codes**: * `200` - Listing and dispatch completed (check `failed_count` for partial publish failures) * `400` - Invalid JSON or missing `app_session_id` * `401` - Authentication failed * `500` - Failed to list open orders *** ## GET /perpetual/orders Retrieve perpetuals order history with pagination. Each order’s `direction` is stored as returned (`long` or `short`) — same idea as `GET /perpetual/open_orders`. **Authentication:** Required **Query Parameters**: | Parameter | Type | Required | Options | Description | | ---------------- | ------- | -------- | ----------------------- | --------------------------------------------------------------------------------------------- | | `app_session_id` | string | Yes | — | Perpetuals account app session ID | | `market` | string | No | — | Exact filter by trading market | | `market_like` | string | No | — | Fuzzy filter by market (contains, case-insensitive) | | `use_cursor` | boolean | No | — | Set `true` to use cursor pagination (first request). See [List pagination](#list-pagination). | | `cursor` | string | No | — | Opaque continuation token from the previous response's `next_cursor`. Omit on the first page. | | `page_size` | integer | No | default `50`, max `100` | Number of orders per page | **Request**: ```http theme={null} GET /perpetual/orders?app_session_id=your-session-id&market=BTCYTEST.USD-PERP&use_cursor=true&page_size=20 ``` **Response**: ```json theme={null} { "orders": [ { "id": "1234567", "order_id": "550e8400-e29b-41d4-a716-446655440000", "app_session_id": "your-session-id", "market": "BTCYTEST.USD-PERP", "price": "35000.00000000", "amount": "0.50000000", "origin_amount": "0.50000000", "fill_amount": "0.20000000", "notional": "17500.00000000", "side": "buy", "type": "limit", "state": "wait", "event": "", "reason": "", "leverage": "10.00000000", "created_at": "2023-12-07T10:30:00.000000Z", "updated_at": "2023-12-07T10:30:05.000000Z", "completed_at": "" } ], "page_size": 20, "next_cursor": "1234520", "has_more": true } ``` **Response Fields**: | Field | Type | Description | | ------------------------- | -------------- | --------------------------------------------------- | | `orders` | array | Array of order objects | | `orders[].id` | string | Internal order record ID | | `orders[].order_id` | string | Order UUID | | `orders[].app_session_id` | string | Perpetuals account app session ID | | `orders[].market` | string | Trading market | | `orders[].price` | decimal string | Order price | | `orders[].amount` | decimal string | Current order amount (remaining to fill) | | `orders[].origin_amount` | decimal string | Original order amount | | `orders[].fill_amount` | decimal string | Amount that has been filled | | `orders[].notional` | decimal string | Notional value (origin\_amount x price) | | `orders[].side` | string | Order side (`buy` or `sell`) | | `orders[].type` | string | Order type (`limit`, `market`) | | `orders[].state` | string | Order state (`pending`, `wait`, `done`, `canceled`) | | `orders[].event` | string | Last order event | | `orders[].reason` | string | Reason for last state change | | `orders[].leverage` | decimal string | Leverage multiplier | | `orders[].created_at` | string | Order creation timestamp | | `orders[].updated_at` | string | Last update timestamp | | `orders[].completed_at` | string | Completion timestamp (empty for open orders) | | `page_size` | integer | Number of items per page | | `next_cursor` | string | Cursor pagination token (empty when no more pages) | | `has_more` | boolean | Whether another page exists | **Status Codes**: * `200` - Orders retrieved successfully * `400` - Invalid query parameters (including malformed `cursor`) * `401` - Authentication failed * `500` - Internal server error *** ## GET /perpetual/open\_orders Retrieve open (unfilled) perpetuals orders. Returns only orders that are currently active in the order book. `direction` on each row is `long` or `short`. **Authentication:** Required **Query Parameters**: | Parameter | Type | Required | Options | Description | | ---------------- | ------- | -------- | ----------------------- | --------------------------------------------------------------------------------------------- | | `app_session_id` | string | Yes | — | Perpetuals account app session ID | | `market` | string | No | — | Exact filter by trading market | | `market_like` | string | No | — | Fuzzy filter by market (contains, case-insensitive) | | `use_cursor` | boolean | No | — | Set `true` to use cursor pagination (first request). See [List pagination](#list-pagination). | | `cursor` | string | No | — | Opaque continuation token from the previous response's `next_cursor`. Omit on the first page. | | `page_size` | integer | No | default `50`, max `100` | Number of orders per page | **Request**: ```http theme={null} GET /perpetual/open_orders?app_session_id=your-session-id&market=BTCYTEST.USD-PERP&use_cursor=true&page_size=20 ``` **Response**: ```json theme={null} { "orders": [ { "id": "1234567", "order_id": "550e8400-e29b-41d4-a716-446655440000", "app_session_id": "your-session-id", "market": "BTCYTEST.USD-PERP", "price": "35000.00000000", "amount": "0.50000000", "origin_amount": "0.50000000", "fill_amount": "0.20000000", "notional": "17500.00000000", "side": "buy", "type": "limit", "state": "wait", "event": "", "reason": "", "leverage": "10.00000000", "created_at": "2023-12-07T10:30:00.000000Z", "updated_at": "2023-12-07T10:30:05.000000Z", "completed_at": "" } ], "page_size": 20, "next_cursor": "1234520", "has_more": false } ``` **Response Fields**: | Field | Type | Description | | ------------------------- | -------------- | ---------------------------------------------------------------- | | `orders` | array | Array of open order objects (same format as `/perpetual/orders`) | | `orders[].id` | string | Internal order record ID | | `orders[].order_id` | string | Order UUID | | `orders[].app_session_id` | string | Perpetuals account app session ID | | `orders[].market` | string | Trading market | | `orders[].price` | decimal string | Order price | | `orders[].amount` | decimal string | Current order amount (remaining to fill) | | `orders[].origin_amount` | decimal string | Original order amount | | `orders[].fill_amount` | decimal string | Amount that has been filled | | `orders[].notional` | decimal string | Notional value (origin\_amount x price) | | `orders[].side` | string | Order side (`buy` or `sell`) | | `orders[].type` | string | Order type (`limit`, `market`) | | `orders[].state` | string | Order state (typically `wait` for open orders) | | `orders[].event` | string | Last order event | | `orders[].reason` | string | Reason for last state change | | `orders[].leverage` | decimal string | Leverage multiplier | | `orders[].created_at` | string | Order creation timestamp | | `orders[].updated_at` | string | Last update timestamp | | `orders[].completed_at` | string | Completion timestamp (empty for open orders) | | `page_size` | integer | Number of items per page | | `next_cursor` | string | Cursor pagination token (empty when no more pages) | | `has_more` | boolean | Whether another page exists | **Note**: This endpoint only returns orders with open states (`wait`, `pending`). For complete order history including filled and cancelled orders, use `/perpetual/orders`. **Status Codes**: * `200` - Open orders retrieved successfully * `400` - Invalid query parameters (including malformed `cursor`) * `401` - Authentication failed * `500` - Internal server error *** ## GET /perpetual/trades Retrieve perpetuals trade history with pagination. Returns only the user's own trades with privacy-focused response format. **Authentication:** Required **Query Parameters**: | Parameter | Type | Required | Options | Description | | ---------------- | ------- | -------- | ----------------------- | --------------------------------------------------------------------------------------------- | | `app_session_id` | string | Yes | — | Perpetuals account app session ID | | `market` | string | No | — | Exact filter by trading market | | `market_like` | string | No | — | Fuzzy filter by market (contains, case-insensitive) | | `start_time` | string | No | RFC3339 or RFC3339Nano | Filter executed\_at >= start\_time | | `end_time` | string | No | RFC3339 or RFC3339Nano | Filter executed\_at \<= end\_time | | `use_cursor` | boolean | No | — | Set `true` to use cursor pagination (first request). See [List pagination](#list-pagination). | | `cursor` | string | No | — | Opaque continuation token from the previous response's `next_cursor`. Omit on the first page. | | `page_size` | integer | No | default `50`, max `100` | Number of trades per page | **Request**: ```http theme={null} GET /perpetual/trades?app_session_id=your-session-id&market=BTCYTEST.USD-PERP&use_cursor=true&page_size=50 ``` **Response**: ```json theme={null} { "trades": [ { "id": "5721092", "order_uuid": "550e8400-e29b-41d4-a716-446655440000", "market": "BTCYTEST.USD-PERP", "base_asset": "BTC", "quote_asset": "USD", "amount": "0.50000000", "price": "35000.00000000", "is_buyer": true, "is_maker": false, "fee": "0.75000000", "exec_type": "trade", "executed_at": "2023-12-07T10:30:00.000000Z", "created_at": "2023-12-07T10:30:01.000000Z" } ], "page_size": 50, "next_cursor": "1701943800000:5721092", "has_more": true } ``` **Response Fields**: | Field | Type | Description | | ---------------------- | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `trades` | array | Array of trade objects | | `trades[].id` | string | Trade record ID | | `trades[].order_uuid` | string | User's own order UUID in this trade (matches create order response) | | `trades[].market` | string | Trading market | | `trades[].base_asset` | string | Base asset symbol (e.g., "BTC") | | `trades[].quote_asset` | string | Quote asset symbol (e.g., "USD") | | `trades[].amount` | decimal string | Trade amount in base asset | | `trades[].price` | decimal string | Trade execution price | | `trades[].is_buyer` | boolean | Whether the user was the buyer | | `trades[].is_maker` | boolean | Whether the user was the maker/liquidity provider | | `trades[].fee` | decimal string | Trading fee charged to the user | | `trades[].exec_type` | string | Execution source: `trade` (normal matched trade), `liquidation` (IOC liquidation fill or cross liquidation netting), `liquidation_takeover` (position taken over for force-settlement during liquidation), `adl` (auto-deleveraging) | | `trades[].executed_at` | string | Trade execution timestamp | | `trades[].created_at` | string | Trade record creation timestamp | | `page_size` | integer | Number of items per page | | `next_cursor` | string | Cursor pagination token (empty when no more pages) | | `has_more` | boolean | Whether another page exists | **Note**: The API response only exposes the user's own order UUID and does not expose counterparty information for privacy reasons. User-relative flags (`is_buyer`, `is_maker`) indicate the user's role in the trade. **Status Codes**: * `200` - Trades retrieved successfully * `400` - Invalid query parameters (including malformed `cursor`) * `401` - Authentication failed * `500` - Internal server error *** ## GET /perpetual/funding-rate/:symbol Retrieve the current funding rate for a specific perpetuals market, plus the previous funding interval when available. **Authentication:** Not required (public endpoint) **Path Parameters**: | Parameter | Type | Required | Options | Description | | --------- | ------ | -------- | ------- | ------------------------------------------ | | `symbol` | string | Yes | — | Trading symbol (e.g., "BTCYTEST.USD-PERP") | **Request**: ```http theme={null} GET /perpetual/funding-rate/BTCYTEST.USD-PERP ``` **Response**: ```json theme={null} { "current_funding_rate": { "market": "BTCYTEST.USD-PERP", "funding_rate": "0.0001", "premium_index": "0.00005", "mark_price": "35000.00000000", "index_price": "35010.00000000", "interval_start": "2023-12-07T10:00:00Z", "interval_end": "2023-12-07T14:00:00Z" }, "previous_funding_rate": { "market": "BTCYTEST.USD-PERP", "funding_rate": "0.00008", "premium_index": "0.00004", "mark_price": "34950.00000000", "index_price": "34960.00000000", "interval_start": "2023-12-07T06:00:00Z", "interval_end": "2023-12-07T10:00:00Z" } } ``` **Response Fields**: | Field | Type | Description | | -------------------------------------- | -------------- | ------------------------------------------------------------------ | | `current_funding_rate` | object | Current funding rate object | | `current_funding_rate.market` | string | Trading market symbol | | `current_funding_rate.funding_rate` | decimal string | Current funding rate | | `current_funding_rate.premium_index` | decimal string | Premium index value | | `current_funding_rate.mark_price` | decimal string | Current mark price | | `current_funding_rate.index_price` | decimal string | Current index price | | `current_funding_rate.interval_start` | string | Start of the current funding interval (ISO 8601 format) | | `current_funding_rate.interval_end` | string | End of the current funding interval (ISO 8601 format) | | `current_funding_rate.created_at` | string | When the current funding rate was recorded (ISO 8601 format) | | `previous_funding_rate` | object | Previous funding interval object (may be omitted if not available) | | `previous_funding_rate.market` | string | Trading market symbol | | `previous_funding_rate.funding_rate` | decimal string | Previous interval funding rate | | `previous_funding_rate.premium_index` | decimal string | Previous interval premium index | | `previous_funding_rate.mark_price` | decimal string | Mark price used for previous interval | | `previous_funding_rate.index_price` | decimal string | Index price used for previous interval | | `previous_funding_rate.interval_start` | string | Start of the previous funding interval (ISO 8601 format) | | `previous_funding_rate.interval_end` | string | End of the previous funding interval (ISO 8601 format) | | `previous_funding_rate.created_at` | string | When the previous funding rate was recorded (ISO 8601 format) | **Status Codes**: * `200` - Funding rate retrieved successfully * `400` - Invalid symbol or validation failed * `500` - Internal server error *** ## GET /perpetual/funding-rates Retrieve funding rate history with pagination. **Authentication:** Not required (public endpoint) **Query Parameters**: | Parameter | Type | Required | Options | Description | | ------------ | ------- | -------- | ----------------------- | --------------------------------------------------------------------------------------------- | | `symbol` | string | No | — | Filter by trading market | | `use_cursor` | boolean | No | — | Set `true` to use cursor pagination (first request). See [List pagination](#list-pagination). | | `cursor` | string | No | — | Opaque continuation token from the previous response's `next_cursor`. Omit on the first page. | | `page_size` | integer | No | default `50`, max `100` | Number of rates per page | **Request** (cursor first page): ```http theme={null} GET /perpetual/funding-rates?symbol=BTCYTEST.USD-PERP&use_cursor=true&page_size=20 ``` **Request** (next page): ```http theme={null} GET /perpetual/funding-rates?symbol=BTCYTEST.USD-PERP&cursor=1701943800000:42&page_size=20 ``` **Response**: ```json theme={null} { "funding_rates": [ { "market": "BTCYTEST.USD-PERP", "funding_rate": "0.0001", "premium_index": "0.00005", "mark_price": "35000.00000000", "index_price": "35010.00000000", "interval_start": "2023-12-07T10:00:00Z", "interval_end": "2023-12-07T14:00:00Z" } ], "page_size": 20, "next_cursor": "1701943800000:42", "has_more": true } ``` **Response Fields**: | Field | Type | Description | | --------------- | ------- | ----------------------------------------------------------------------------------- | | `funding_rates` | array | Array of funding rate objects (same structure as `/perpetual/funding-rate/:symbol`) | | `page_size` | integer | Number of rates per page | | `next_cursor` | string | Cursor pagination token (empty when no more pages) | | `has_more` | boolean | Whether another page exists | **Status Codes**: * `200` - Funding rates retrieved successfully * `400` - Invalid query parameters (including malformed `cursor`) * `500` - Internal server error *** ## GET /perpetual/account/funding-payments Retrieve funding payment history for the specified app session with pagination. **Authentication:** Required **Query Parameters**: | Parameter | Type | Required | Options | Description | | ---------------- | ------- | -------- | ----------------------- | --------------------------------------------------------------------------------------------- | | `app_session_id` | string | Yes | — | App session identifier passed by frontend | | `interval_start` | string | No | ISO 8601 format | Filter by funding interval start time | | `use_cursor` | boolean | No | — | Set `true` to use cursor pagination (first request). See [List pagination](#list-pagination). | | `cursor` | string | No | — | Opaque continuation token from the previous response's `next_cursor`. Omit on the first page. | | `page_size` | integer | No | default `50`, max `100` | Number of payments per page | **Request**: ```http theme={null} GET /perpetual/account/funding-payments?app_session_id=your-session-id&use_cursor=true&page_size=20 ``` **Response**: ```json theme={null} { "funding_payments": [ { "id": "550e8400-e29b-41d4-a716-446655440000", "market": "BTCYTEST.USD-PERP", "account_id": "550e8400-e29b-41d4-a716-446655440001", "position_id": "550e8400-e29b-41d4-a716-446655440002", "side": "long", "position_size": "1.50000000", "mark_price": "35000.00000000", "funding_rate": "0.0001", "funding_amount": "5.25000000", "interval_start": "2023-12-07T10:00:00Z", "interval_end": "2023-12-07T14:00:00Z", "created_at": "2023-12-07T14:00:00Z" } ], "page_size": 20, "next_cursor": "1701943800000:550e8400-e29b-41d4-a716-446655440000", "has_more": true } ``` **Response Fields**: | Field | Type | Description | | ----------------------------------- | -------------- | ------------------------------------------------------------------------------------------- | | `funding_payments` | array | Array of funding payment objects | | `funding_payments[].id` | string | Funding payment ID (UUID) | | `funding_payments[].market` | string | Trading market | | `funding_payments[].account_id` | string | Perpetuals account ID (UUID) | | `funding_payments[].position_id` | string | Position ID (UUID) | | `funding_payments[].side` | string | Position side (`long` or `short`) | | `funding_payments[].position_size` | decimal string | Position size at the time of funding payment | | `funding_payments[].mark_price` | decimal string | Mark price at the time of funding payment | | `funding_payments[].funding_rate` | decimal string | Funding rate applied | | `funding_payments[].funding_amount` | decimal string | Funding payment amount (positive for long positions receiving payment, negative for paying) | | `funding_payments[].interval_start` | string | Start of the funding interval (ISO 8601 format) | | `funding_payments[].interval_end` | string | End of the funding interval (ISO 8601 format) | | `funding_payments[].created_at` | string | When the funding payment was recorded (ISO 8601 format) | | `next_cursor` | string | Opaque next-page token (empty when no more pages) | | `has_more` | boolean | Whether another page exists | | `page_size` | integer | Number of payments per page | **Status Codes**: * `200` - Funding payments retrieved successfully * `400` - Invalid query parameters (including malformed `cursor`) or missing app\_session\_id * `401` - Authentication failed * `500` - Internal server error *** ## GET /perpetual/position/funding-payments Retrieve funding payment history for a specific position within the specified app session, with pagination. **Authentication:** Required **Query Parameters**: | Parameter | Type | Required | Options | Description | | ---------------- | ------- | -------- | ----------------------- | --------------------------------------------------------------------------------------------- | | `app_session_id` | string | Yes | — | App session identifier passed by frontend | | `position_id` | string | Yes | — | Position ID (UUID) | | `interval_start` | string | No | ISO 8601 format | Filter by funding interval start time | | `use_cursor` | boolean | No | — | Set `true` to use cursor pagination (first request). See [List pagination](#list-pagination). | | `cursor` | string | No | — | Opaque continuation token from the previous response's `next_cursor`. Omit on the first page. | | `page_size` | integer | No | default `50`, max `100` | Number of payments per page | **Request**: ```http theme={null} GET /perpetual/position/funding-payments?app_session_id=your-session-id&position_id=550e8400-e29b-41d4-a716-446655440002&use_cursor=true&page_size=20 ``` **Response**: Same format as `/perpetual/account/funding-payments` (array of funding payment objects with pagination metadata) **Status Codes**: * `200` - Funding payments retrieved successfully * `400` - Invalid query parameters (including malformed `cursor`) or missing position\_id/app\_session\_id * `401` - Authentication failed * `500` - Internal server error # Reference Source: https://docs.yellow.pro/api-and-programmatic-access/reference API reference: rate limits, data types, and implementation notes. ## Rate Limiting Rate limiting is enforced to ensure fair usage: * Rate limits apply per endpoint and account * Rate limit information is included in response headers * Exceeding a limit returns a `429` response *** ## Data Types ### Decimal Values All monetary and quantity values are represented as strings in decimal format to maintain precision: ```json theme={null} { "amount": "1.50000000", "price": "35000.00000000" } ``` ### Timestamps Timestamps are provided in milliseconds since Unix epoch: ```json theme={null} { "server_time": 1640995200000 } ``` ### UUIDs Order UUIDs follow standard UUID format: ```json theme={null} { "order_uuid": "550e8400-e29b-41d4-a716-446655440000" } ``` *** ## Pagination List endpoints use **cursor-based** pagination. You walk through results by following the `next_cursor` returned with each page: — send `use_cursor=true` (and optionally `page_size`). Read `next_cursor` and `has_more` from the response. — send `cursor=` from the previous response. Repeat while `has_more` is `true`. **Query parameters** | Parameter | Type | Description | | ------------ | ------- | --------------------------------------------------------------------------------------------- | | `use_cursor` | boolean | Set `true` to use cursor pagination. Send it on the first request. | | `cursor` | string | Opaque continuation token from the previous response's `next_cursor`. Omit on the first page. | | `page_size` | integer | Items per page. Default `50`, maximum `100`. | **Response fields** | Field | Type | Description | | ------------- | ------- | -------------------------------------------------------------------------------- | | `next_cursor` | string | Token to pass as `cursor` for the next page. Empty when there are no more pages. | | `has_more` | boolean | Whether another page exists. | | `page_size` | integer | Items per page. | Always treat `cursor` values as opaque — do not parse or construct them. A malformed `cursor` returns `400` with `"error": "invalid_cursor"`. # Signing Requests With API Keys Source: https://docs.yellow.pro/api-and-programmatic-access/signing-requests-with-api-keys Sign authenticated API requests with HMAC-SHA256 using your API key. API key authentication lets you call authenticated endpoints from servers and scripts without the interactive wallet signing flow. Every authenticated request carries three headers, and the signature is recomputed per request from the request contents. Your API secret is used to compute signatures and is **never sent** in a request. Never commit it to version control, log it, or expose it in client-side code. Store it in an environment variable or a secrets manager. ## Required headers | Header | Value | | ------------- | ----------------------------------------------- | | `X-API-KEY` | Your API key | | `X-TIMESTAMP` | Request time as a **Unix timestamp in seconds** | | `X-SIGNATURE` | Hex-encoded HMAC-SHA256 signature (see below) | ## How the signature is computed The signature is `HMAC-SHA256(secret, prehash)`, hex-encoded, where: ``` prehash = METHOD + PATH + TIMESTAMP + CANONICAL ``` | Part | Description | | ----------- | ------------------------------------------------------------------------ | | `METHOD` | Uppercase HTTP method, e.g. `GET`, `POST`, `DELETE` | | `PATH` | Request path only, **without** the query string, e.g. `/perpetual/order` | | `TIMESTAMP` | The same value sent in `X-TIMESTAMP` (Unix seconds) | | `CANONICAL` | The canonical string built from the request parameters (below) | ### Building the canonical string The canonical string is built from sorted parameters joined into `key=value` pairs with a `|` separator. Where the parameters come from depends on the method: Use the **JSON request body**. Sort its top-level keys alphabetically and join them: ``` key1=value1|key2=value2|... ``` For a body of `{"market":"BTCUSDT","side":"buy","type":"limit","amount":"0.5","price":"35000"}`: ``` amount=0.5|market=BTCUSDT|price=35000|side=buy|type=limit ``` Send decimal values (`amount`, `price`, …) as **strings**, exactly as they appear in the body you transmit. This keeps the signed value identical to the sent value and avoids floating-point formatting differences. Use the **query parameters**. Sort the parameter names alphabetically and join them. If a parameter appears multiple times, sort its values and join them with commas: ``` key1=value1|key2=value2|... ``` For `GET /perpetual/orders?market=BTCUSDT&app_session_id=your-session-id`: ``` app_session_id=your-session-id|market=BTCUSDT ``` A request with no query parameters has an **empty** canonical string. ### Worked example For `POST /perpetual/order` at timestamp `1701938200` with the body above: ``` prehash = POST/perpetual/order1701938200amount=0.5|market=BTCUSDT|price=35000|side=buy|type=limit signature = hex( HMAC_SHA256(your_api_secret, prehash) ) ``` The request then carries: ```http theme={null} X-API-KEY: X-TIMESTAMP: 1701938200 X-SIGNATURE: Content-Type: application/json ``` ## Code examples ```javascript theme={null} const crypto = require('crypto'); function buildAuthHeaders({ method, path, query = {}, body = null, apiKey, apiSecret }) { const m = method.toUpperCase(); const timestamp = Math.floor(Date.now() / 1000).toString(); // Unix seconds const canonical = (m === 'GET' || m === 'DELETE') ? canonicalFromQuery(query) : canonicalFromBody(body || {}); const prehash = m + path + timestamp + canonical; const signature = crypto.createHmac('sha256', apiSecret).update(prehash).digest('hex'); return { 'X-API-KEY': apiKey, 'X-TIMESTAMP': timestamp, 'X-SIGNATURE': signature, 'Content-Type': 'application/json', }; } function canonicalFromBody(body) { return Object.keys(body).sort().map((k) => `${k}=${body[k]}`).join('|'); } function canonicalFromQuery(query) { return Object.keys(query).sort().map((k) => { const v = query[k]; const value = Array.isArray(v) ? [...v].sort().join(',') : v; return `${k}=${value}`; }).join('|'); } // Example: place a perpetual order const body = { market: 'BTCUSDT', side: 'buy', type: 'limit', amount: '0.5', price: '35000' }; const headers = buildAuthHeaders({ method: 'POST', path: '/perpetual/order', body, apiKey: process.env.API_KEY, apiSecret: process.env.API_SECRET, }); await fetch('https://trade.api.yellow.pro/perpetual/order', { method: 'POST', headers, body: JSON.stringify(body), // must match the body used for the signature }); ``` ```python theme={null} import hashlib import hmac import json import time import requests def build_auth_headers(method, path, *, api_key, api_secret, query=None, body=None): m = method.upper() timestamp = str(int(time.time())) # Unix seconds if m in ("GET", "DELETE"): canonical = canonical_from_query(query or {}) else: canonical = canonical_from_body(body or {}) prehash = f"{m}{path}{timestamp}{canonical}" signature = hmac.new( api_secret.encode(), prehash.encode(), hashlib.sha256 ).hexdigest() return { "X-API-KEY": api_key, "X-TIMESTAMP": timestamp, "X-SIGNATURE": signature, "Content-Type": "application/json", } def canonical_from_body(body): return "|".join(f"{k}={body[k]}" for k in sorted(body)) def canonical_from_query(query): parts = [] for k in sorted(query): v = query[k] if isinstance(v, (list, tuple)): v = ",".join(sorted(map(str, v))) parts.append(f"{k}={v}") return "|".join(parts) # Example: place a perpetual order body = {"market": "BTCUSDT", "side": "buy", "type": "limit", "amount": "0.5", "price": "35000"} headers = build_auth_headers("POST", "/perpetual/order", api_key=API_KEY, api_secret=API_SECRET, body=body) requests.post( "https://trade.api.yellow.pro/perpetual/order", headers=headers, data=json.dumps(body), # must match the body used for the signature ) ``` ## Common pitfalls * **Sign the body you send.** The JSON you transmit must contain exactly the values used to build the canonical string. Re-serializing or reordering after signing will invalidate the signature. * **Seconds, not milliseconds.** `X-TIMESTAMP` is Unix **seconds**. Sending milliseconds will fail verification. * **Path only.** Exclude the query string from `PATH`; query parameters belong in the canonical string for `GET`/`DELETE`. * **Sort keys.** Both body keys and query keys must be sorted alphabetically before joining. # Spot Trading API Source: https://docs.yellow.pro/api-and-programmatic-access/spot-trading-api Spot trading API: accounts, orders, trades, and fee rates. The spot trading API provides endpoints for managing spot trading accounts, placing and canceling orders, and retrieving trade history. ## GET /spot/exchangeInfo Retrieve exchange information including available spot markets and their details. **Authentication:** Not required **`maker_fee_rate` and `taker_fee_rate` here are outdated.** The values returned in `exchangeInfo` are static, indicative defaults and do **not** reflect the fees actually applied to your account (fee tiers, promotions, etc.). For the authoritative, account-specific rates always use [`GET /spot/account/market-fee-rate`](#get-spot-account-market-fee-rate). **Response**: ```json theme={null} { "timezone": "UTC", "server_time": 1781702612915, "assets": [ { "asset": "ETH", "name": "Ethereum", "decimals": 17, "display_precision": 8, "is_stablecoin": false, "min_withdraw_amount": "0.005" }, { "asset": "USDT", "name": "Tether USD", "decimals": 6, "display_precision": 2, "is_stablecoin": true, "min_withdraw_amount": "5" } ], "symbols": [ { "symbol": "ETHUSDT", "status": "active", "base_asset_name": "Ethereum", "base_asset": "ETH", "base_asset_precision": 17, "quote_asset_name": "Tether USD", "quote_asset": "USDT", "quote_asset_precision": 6, "amount_precision": 8, "price_precision": 8, "maker_fee_rate": "0.0008", "taker_fee_rate": "0.001", "market_order_slippage_tolerance": "0.050000", "max_allowed_leverage": "", "filters": [ {"filter_type": "DEPTH_MERGE", "config": {"depth_level": ["0.01", "0.1", "1", "10", "100"]}}, {"filter_type": "LOT_SIZE", "config": {"step_size": "0.001", "min_qty": "0.001", "max_qty": "50000"}}, {"filter_type": "MIN_NOTIONAL", "config": {"min_notional": "1"}}, {"filter_type": "PRICE_FILTER", "config": {"tick_size": "0.01", "min_price": "1000", "max_price": "100000"}} ] } ] } ``` **Response Fields**: | Field | Type | Description | | ------------------------------------------- | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `timezone` | string | Exchange timezone | | `server_time` | integer | Current server timestamp in milliseconds | | `assets` | array | Array of supported assets | | `assets[].asset` | string | Asset symbol (e.g., "ETH") | | `assets[].name` | string | Human-readable asset name | | `assets[].decimals` | integer | On-chain token decimals | | `assets[].display_precision` | integer | Display precision for the asset in UI | | `assets[].is_stablecoin` | boolean | Whether the asset is a stablecoin | | `assets[].min_withdraw_amount` | decimal string | Minimum withdrawal amount for the asset | | `symbols` | array | Array of available spot trading symbols | | `symbols[].symbol` | string | Trading symbol name (e.g., "ETHUSDT") | | `symbols[].status` | string | Market status (e.g., "active") | | `symbols[].base_asset_name` | string | Display name for base asset | | `symbols[].base_asset` | string | Base asset symbol (e.g., "ETH") | | `symbols[].base_asset_precision` | integer | Decimal precision for base asset | | `symbols[].quote_asset_name` | string | Display name for quote asset | | `symbols[].quote_asset` | string | Quote asset symbol (e.g., "USDT") | | `symbols[].quote_asset_precision` | integer | Decimal precision for quote asset | | `symbols[].amount_precision` | integer | Decimal precision for amount (base asset) | | `symbols[].price_precision` | integer | Decimal precision for price (quote asset) | | `symbols[].maker_fee_rate` | decimal string | ⚠️ **Outdated** — static indicative default, not your account's effective rate. Use [`GET /spot/account/market-fee-rate`](#get-spot-account-market-fee-rate). | | `symbols[].taker_fee_rate` | decimal string | ⚠️ **Outdated** — static indicative default, not your account's effective rate. Use [`GET /spot/account/market-fee-rate`](#get-spot-account-market-fee-rate). | | `symbols[].market_order_slippage_tolerance` | decimal string | Max slippage tolerated for market orders on this symbol | | `symbols[].max_allowed_leverage` | decimal string | Max allowed leverage (empty for spot) | | `symbols[].filters` | array | Trading rules (PRICE\_FILTER, LOT\_SIZE, MIN\_NOTIONAL, DEPTH\_MERGE) | **Status Codes**: * `200` - Exchange information retrieved successfully * `500` - Internal server error *** ## GET /spot/networks Retrieve supported blockchain networks and the tokens available for deposit and withdrawal on each network. **Authentication:** Not required **Response**: ```json theme={null} { "networks": [ { "chain_id": 1, "name": "ethereum", "custody_address": "0x5FbDB2315678afecb367f032d93F642f64180aa3", "tokens": [ { "symbol": "ETH", "contract_address": "0x0000000000000000000000000000000000000000", "decimals": 18, "can_deposit": true, "can_withdraw": true }, { "symbol": "USDC", "contract_address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", "decimals": 6, "can_deposit": true, "can_withdraw": true } ] }, { "chain_id": 42161, "name": "arbitrum", "custody_address": "0xABC123def456789012345678901234567890abcd", "tokens": [ { "symbol": "ETH", "contract_address": "0x0000000000000000000000000000000000000000", "decimals": 18, "can_deposit": true, "can_withdraw": true } ] } ] } ``` **Response Fields**: | Field | Type | Description | | -------------------------------------- | ------- | ------------------------------------------------------------------------ | | `networks` | array | Array of supported blockchain networks | | `networks[].chain_id` | integer | EVM chain ID (e.g., 1 for Ethereum mainnet, 42161 for Arbitrum) | | `networks[].name` | string | Human-readable network name | | `networks[].custody_address` | string | Custody contract address on this network (deposit destination) | | `networks[].tokens` | array | Array of tokens available on this network | | `networks[].tokens[].symbol` | string | Asset symbol (e.g., "ETH", "USDC") | | `networks[].tokens[].contract_address` | string | Token ERC-20 contract address (`0x000...000` for native ETH) | | `networks[].tokens[].decimals` | integer | On-chain token decimals | | `networks[].tokens[].can_deposit` | boolean | Whether deposits are currently enabled for this token on this network | | `networks[].tokens[].can_withdraw` | boolean | Whether withdrawals are currently enabled for this token on this network | **Status Codes**: * `200` - Networks retrieved successfully *** ## GET /spot/accounts Retrieve all spot accounts for the authenticated user. **Authentication:** Required **Response**: ```json theme={null} [ { "id": "550e8400-e29b-41d4-a716-446655440000", "app_session_id": "your-session-id", "owner": "0x1234567890abcdef1234567890abcdef12345678", "balances": [ { "asset_symbol": "BTC", "asset_name": "Bitcoin", "total_balance": "1.50000000", "available_balance": "1.20000000", "locked_balance": "0.30000000", "total_balance_usd": "169343.931544", "available_balance_usd": "135475.145235", "locked_balance_usd": "33868.786309", "last_updated": "2023-12-07T10:30:00.000000Z" }, { "asset_symbol": "USDT", "asset_name": "Tether USD", "total_balance": "10000.00000000", "available_balance": "8500.00000000", "locked_balance": "1500.00000000", "total_balance_usd": "10000.00000000", "available_balance_usd": "8500.00000000", "locked_balance_usd": "1500.00000000", "last_updated": "2023-12-07T10:30:00.000000Z" } ], "usdt_account_value": "179343.931544", "state": "active", "opened_at": "2023-12-01T08:00:00.000000Z" } ] ``` **Response Fields**: | Field | Type | Description | | ---------------------------------- | -------------- | ------------------------------------------------------------------ | | `id` | string | Unique spot account identifier (UUID) | | `app_session_id` | string | Application session identifier | | `owner` | string | Owner's Ethereum wallet address | | `balances` | array | Array of balance objects | | `balances[].asset_symbol` | string | Asset symbol (e.g., "BTC", "USDT") | | `balances[].asset_name` | string | Human-readable asset display name (e.g., "Bitcoin") | | `balances[].total_balance` | decimal string | Total balance (available + locked) | | `balances[].available_balance` | decimal string | Balance available for trading | | `balances[].locked_balance` | decimal string | Balance locked in open orders | | `balances[].total_balance_usd` | decimal string | Total balance valued in stablecoin (USD/USDT); `"0"` when no price | | `balances[].available_balance_usd` | decimal string | Available balance valued in stablecoin; `"0"` when no price | | `balances[].locked_balance_usd` | decimal string | Locked balance valued in stablecoin; `"0"` when no price | | `balances[].last_updated` | string | Last balance update timestamp | | `usdt_account_value` | decimal string | Total account value in USDT | | `state` | string | Account state (`active`, `closed`) | | `opened_at` | string | Account creation timestamp | **Status Codes**: * `200` - Accounts retrieved successfully * `401` - Authentication failed * `500` - Internal server error ## GET /spot/account Retrieve information for a specific spot account. **Authentication:** Required **Query Parameters**: | Parameter | Type | Required | Options | Description | | ---------------- | ------ | -------- | ------- | ------------------------------------------------------------- | | `app_session_id` | string | Yes | — | Spot account app session ID | | `asset` | string | No | — | Exact asset symbol match on `asset_symbol` | | `asset_like` | string | No | — | Case-insensitive substring (contains) match on `asset_symbol` | **Request**: ```http theme={null} GET /spot/account?app_session_id=your-session-id ``` **Response**: ```json theme={null} { "id": "550e8400-e29b-41d4-a716-446655440000", "app_session_id": "your-session-id", "owner": "0x1234567890abcdef1234567890abcdef12345678", "balances": [ { "asset_symbol": "BTC", "asset_name": "Bitcoin", "total_balance": "1.50000000", "available_balance": "1.20000000", "locked_balance": "0.30000000", "total_balance_usd": "169343.931544", "available_balance_usd": "135475.145235", "locked_balance_usd": "33868.786309", "last_updated": "2023-12-07T10:30:00.000000Z" } ], "usdt_account_value": "169343.931544", "state": "active", "opened_at": "2023-12-01T08:00:00.000000Z" } ``` **Status Codes**: * `200` - Account retrieved successfully * `400` - Missing app\_session\_id parameter * `401` - Authentication failed * `404` - Account not found * `500` - Internal server error ## GET /spot/account/market-fee-rate Retrieve the effective spot maker/taker fee rates for a single market on a given account. **Authentication:** Required (read:spot scope) **Query Parameters**: | Parameter | Type | Required | Options | Description | | ---------------- | ------ | -------- | ------- | -------------------------------- | | `app_session_id` | string | Yes | — | Spot account app session ID | | `market` | string | Yes | — | Trading market (e.g., "BTCUSDT") | **Request**: ```http theme={null} GET /spot/account/market-fee-rate?app_session_id=your-session-id&market=BTCUSDT ``` **Response**: ```json theme={null} [ { "app_session_id": "your-session-id", "market": "BTCUSDT", "maker_fee_rate": "0.001", "taker_fee_rate": "0.0015", "source": "fee_tier", "fee_tier_version": 3 } ] ``` **Response Fields**: The response is a JSON array containing a single fee-rate object: | Field | Type | Description | | ------------------ | -------------- | ------------------------------------------------- | | `app_session_id` | string | Spot account app session ID | | `market` | string | Trading market | | `maker_fee_rate` | decimal string | Effective maker fee rate | | `taker_fee_rate` | decimal string | Effective taker fee rate | | `source` | string | Origin of the applied fee rate (e.g., `fee_tier`) | | `fee_tier_version` | integer | Version of the fee tier configuration applied | **Status Codes**: * `200` - Fee rates retrieved successfully * `400` - Missing `app_session_id` or `market` parameter * `401` - Authentication failed * `500` - Internal server error ## POST /spot/order Create a new spot trading order. **Authentication:** Required **Request Body**: ```json theme={null} { "app_session_id": "your-session-id", "market": "BTCUSDT", "side": "buy", "type": "limit", "amount": "0.5", "price": "35000", "time_in_force": "gtc", "trigger_price": "34000" } ``` **Request Parameters**: | Parameter | Type | Required | Options | Description | | ---------------- | ------ | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------- | | `app_session_id` | string | Yes | — | Spot account app session ID | | `market` | string | Yes | — | Trading market (e.g., "BTCUSDT", "ETHUSDC") | | `side` | string | Yes | `buy`, `sell` | Order side | | `type` | string | Yes | `limit`, `market` | Order type | | `amount` | string | Yes | — | Order amount in base asset (decimal format) | | `price` | string | No | — | Limit price (required for `limit` orders, ignored for `market` orders) | | `time_in_force` | string | No | `gtc` (Good-Till-Cancelled), `ioc` (Immediate-Or-Cancel), `fok` (Fill-Or-Kill); defaults to `GTC` for `limit` orders, `IOC` for `market` orders | Time in force | | `trigger_price` | string | No | — | Trigger price for stop/trigger order types (decimal string) | **Response**: ```json theme={null} { "order_uuid": "550e8400-e29b-41d4-a716-446655440000" } ``` **Response Fields**: | Field | Type | Description | | ------------ | ------ | ------------------------- | | `order_uuid` | string | UUID of the created order | **Status Codes**: * `200` - Order created successfully * `400` - Invalid request parameters or validation failed (for example, insufficient balance) * `401` - Authentication failed * `500` - Internal server error **Error response** (typical for `400`): ```json theme={null} { "error": "insufficient_balance", "message": "insufficient available balance" } ``` * `error`: Machine-readable error code (`snake_case`), e.g. `insufficient_balance`. * `message`: Human-readable detail. ## DELETE /spot/order Cancel an existing spot order. **Authentication:** Required **Request Body**: ```json theme={null} { "app_session_id": "your-session-id", "market": "BTCUSDT", "order_uuid": "550e8400-e29b-41d4-a716-446655440000", "type": "limit" } ``` **Request Parameters**: | Parameter | Type | Required | Options | Description | | ---------------- | ------ | -------- | ------- | --------------------------- | | `app_session_id` | string | Yes | — | Spot account app session ID | | `market` | string | Yes | — | Trading market | | `order_uuid` | string | Yes | — | UUID of the order to cancel | | `type` | string | Yes | — | Order type | **Response**: ```json theme={null} { "message": "Spot order cancellation request sent successfully" } ``` **Status Codes**: * `200` - Cancellation request sent successfully * `400` - Invalid request or missing parameters * `401` - Authentication failed * `500` - Internal server error ## DELETE /spot/orders Cancel all open spot orders for an account, optionally limited to a single market. **Authentication:** Required (trade:spot scope) **Request Body**: ```json theme={null} { "app_session_id": "your-session-id", "market": "BTCUSDT" } ``` **Request Parameters**: | Parameter | Type | Required | Options | Description | | ---------------- | ------ | -------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------ | | `app_session_id` | string | Yes | — | Spot account app session ID | | `market` | string | No | — | Trading market. When provided, only open orders for that market are cancelled; when omitted, open orders across all markets are cancelled. | **Response**: ```json theme={null} { "message": "Cancel requests sent for 3 orders in market BTCUSDT", "canceled_count": 3, "failed_count": 0 } ``` When there are no open orders to cancel: ```json theme={null} { "message": "No open orders to cancel", "canceled_count": 0 } ``` **Response Fields**: | Field | Type | Description | | ---------------- | ------- | ------------------------------------------------------------------------------------------------------ | | `message` | string | Human-readable summary of the cancellation request | | `canceled_count` | integer | Number of orders for which a cancellation request was sent | | `failed_count` | integer | Number of orders whose cancellation request could not be sent (omitted when there were no open orders) | **Status Codes**: * `200` - Cancellation requests sent (or no open orders to cancel) * `400` - Invalid request body or missing `app_session_id` * `401` - Authentication failed * `403` - Not authorized to cancel orders for this account * `404` - Spot account not found * `500` - Internal server error ## GET /spot/open\_orders Retrieve open spot orders with cursor pagination. **Authentication:** Required **Pagination:** Spot list endpoints use cursor-based pagination. See [Pagination](/api-and-programmatic-access/reference#pagination) for the shared model. **Query Parameters**: | Parameter | Type | Required | Options | Description | | ---------------- | ------- | -------- | ----------------------- | --------------------------------------------------------------------------------------------- | | `app_session_id` | string | Yes | — | Spot account app session ID | | `asset` | string | No | — | Case-insensitive fuzzy filter on `asset_symbol` (contains match) | | `market` | string | No | — | Filter by trading market | | `use_cursor` | boolean | No | — | Set `true` to use cursor pagination (use on the first request). | | `cursor` | string | No | — | Opaque continuation token from the previous response's `next_cursor`. Omit on the first page. | | `page_size` | integer | No | default `50`, max `100` | Number of orders per page | **Request** (first page): ```http theme={null} GET /spot/open_orders?app_session_id=your-session-id&market=BTCUSDT&use_cursor=true&page_size=20 ``` **Request** (next page): ```http theme={null} GET /spot/open_orders?app_session_id=your-session-id&market=BTCUSDT&cursor=eyJpZCI6MTIzNH0&page_size=20 ``` **Response**: ```json theme={null} { "orders": [ { "id": "1234", "order_id": "550e8400-e29b-41d4-a716-446655440000", "channel_id": "your-session-id", "market": "BTCUSDT", "price": "35000.00000000", "amount": "0.50000000", "origin_amount": "0.50000000", "notional": "17500.00000000", "side": "buy", "type": "limit", "state": "wait", "event": "", "reason": "", "created_at": "2023-12-07T10:30:00.000000Z", "updated_at": "2023-12-07T10:30:00.000000Z", "completed_at": "" } ], "next_cursor": "eyJpZCI6MTIzNH0", "has_more": true, "page_size": 20 } ``` **Response Fields**: | Field | Type | Description | | ------------------------ | -------------- | --------------------------------------------------------------------- | | `orders` | array | Array of order objects | | `orders[].id` | string | Internal order record ID | | `orders[].order_id` | string | Order UUID | | `orders[].channel_id` | string | Spot account app session ID | | `orders[].market` | string | Trading market | | `orders[].price` | decimal string | Order price | | `orders[].amount` | decimal string | Current order amount (may be partially filled) | | `orders[].origin_amount` | decimal string | Original order amount | | `orders[].notional` | decimal string | Notional value (amount x price) | | `orders[].side` | string | Order side (`buy` or `sell`) | | `orders[].type` | string | Order type (`limit` or `market`) | | `orders[].state` | string | Order state (`wait`, `done`, `canceled`) | | `orders[].event` | string | Last order event (empty string) | | `orders[].reason` | string | Reason for last state change (empty string) | | `orders[].created_at` | string | Order creation timestamp | | `orders[].updated_at` | string | Last update timestamp | | `orders[].completed_at` | string | Completion timestamp (empty for open orders) | | `next_cursor` | string | Token to pass as `cursor` for the next page; empty when no more pages | | `has_more` | boolean | Whether another page exists | | `page_size` | integer | Number of orders per page | **Status Codes**: * `200` - Orders retrieved successfully * `400` - Invalid query parameters (including malformed `cursor`) * `401` - Authentication failed * `500` - Internal server error ## GET /spot/orders Retrieve spot order history with cursor pagination. **Authentication:** Required **Pagination:** This endpoint uses cursor-based pagination. See [Pagination](/api-and-programmatic-access/reference#pagination). **Query Parameters**: | Parameter | Type | Required | Options | Description | | ---------------- | ------- | -------- | ----------------------- | --------------------------------------------------------------------------------------------- | | `app_session_id` | string | Yes | — | Spot account app session ID | | `market` | string | No | — | Filter by trading market | | `use_cursor` | boolean | No | — | Set `true` to use cursor pagination (use on the first request). | | `cursor` | string | No | — | Opaque continuation token from the previous response's `next_cursor`. Omit on the first page. | | `page_size` | integer | No | default `50`, max `100` | Number of orders per page | **Request** (first page): ```http theme={null} GET /spot/orders?app_session_id=your-session-id&use_cursor=true&page_size=50 ``` **Request** (next page): ```http theme={null} GET /spot/orders?app_session_id=your-session-id&cursor=eyJpZCI6OTl9&page_size=50 ``` **Response**: Same format as `/spot/open_orders` but includes all orders (open, filled, and cancelled) **Status Codes**: * `200` - Orders retrieved successfully * `400` - Invalid query parameters (including malformed `cursor`) * `401` - Authentication failed * `500` - Internal server error ## GET /spot/trades Retrieve spot trade history with cursor pagination. **Authentication:** Required **Pagination:** This endpoint uses cursor-based pagination. See [Pagination](/api-and-programmatic-access/reference#pagination). **Query Parameters**: | Parameter | Type | Required | Options | Description | | ---------------- | ------- | -------- | ----------------------- | --------------------------------------------------------------------------------------------- | | `app_session_id` | string | Yes | — | Spot account app session ID | | `market` | string | No | — | Filter by trading market | | `use_cursor` | boolean | No | — | Set `true` to use cursor pagination (use on the first request). | | `cursor` | string | No | — | Opaque continuation token from the previous response's `next_cursor`. Omit on the first page. | | `page_size` | integer | No | default `50`, max `100` | Number of trades per page | **Request** (first page): ```http theme={null} GET /spot/trades?app_session_id=your-session-id&market=BTCUSDT&use_cursor=true&page_size=50 ``` **Request** (next page): ```http theme={null} GET /spot/trades?app_session_id=your-session-id&market=BTCUSDT&cursor=eyJpZCI6NTcyMTA5Mn0&page_size=50 ``` **Response**: ```json theme={null} { "trades": [ { "id": "5721092", "order_id": "12345", "market": "BTCUSDT", "amount": "0.50000000", "price": "35000.00000000", "is_buyer": true, "is_maker": false, "executed_at": "2023-12-07T10:30:00.000000Z", "created_at": "2023-12-07T10:30:01.000000Z" } ], "next_cursor": "eyJpZCI6NTcyMTA5Mn0", "has_more": true, "page_size": 50 } ``` **Response Fields**: | Field | Type | Description | | ---------------------- | -------------- | --------------------------------------------------------------------- | | `trades` | array | Array of trade objects | | `trades[].id` | string | Internal trade record ID | | `trades[].order_id` | string | User's own order ID in this trade (numeric) | | `trades[].market` | string | Trading market | | `trades[].amount` | decimal string | Trade amount in base asset | | `trades[].price` | decimal string | Trade execution price | | `trades[].is_buyer` | boolean | Whether the user was the buyer in this trade | | `trades[].is_maker` | boolean | Whether the user was the maker (liquidity provider) in this trade | | `trades[].executed_at` | string | Trade execution timestamp | | `trades[].created_at` | string | Trade record creation timestamp | | `next_cursor` | string | Token to pass as `cursor` for the next page; empty when no more pages | | `has_more` | boolean | Whether another page exists | | `page_size` | integer | Number of trades per page | **Note**: The API response only exposes the user's own order ID and does not expose counterparty information for privacy reasons. It provides user-relative flags (`is_buyer`, `is_maker`) to indicate the user's role in the trade. **Status Codes**: * `200` - Trades retrieved successfully * `400` - Invalid query parameters (including malformed `cursor`) * `401` - Authentication failed * `500` - Internal server error ## GET /spot/deposits Retrieve spot deposit history with cursor pagination. **Authentication:** Required **Pagination:** This endpoint uses cursor-based pagination. See [Pagination](/api-and-programmatic-access/reference#pagination). **Query Parameters**: | Parameter | Type | Required | Options | Description | | ---------------- | ------- | -------- | ----------------------- | --------------------------------------------------------------------------------------------- | | `app_session_id` | string | Yes | — | Spot account app session ID | | `use_cursor` | boolean | No | — | Set `true` to use cursor pagination (use on the first request). | | `cursor` | string | No | — | Opaque continuation token from the previous response's `next_cursor`. Omit on the first page. | | `page_size` | integer | No | default `50`, max `100` | Number of deposits per page | **Request** (first page): ```http theme={null} GET /spot/deposits?app_session_id=your-session-id&use_cursor=true&page_size=50 ``` **Request** (next page): ```http theme={null} GET /spot/deposits?app_session_id=your-session-id&cursor=eyJpZCI6Nn0&page_size=50 ``` **Response**: ```json theme={null} { "deposits": [ { "spot_account_id": "550e8400-e29b-41d4-a716-446655440001", "asset_symbol": "USDT", "amount": "10000.00000000", "transaction_hash": "0xabcdef1234567890", "created_at": "2023-12-07T10:30:01.000000Z", "deposited_at": "2023-12-07T10:30:00.000000Z", "chain_id": 1 } ], "next_cursor": "eyJpZCI6Nn0", "has_more": true, "page_size": 50 } ``` **Response Fields**: | Field | Type | Description | | ----------------------------- | -------------- | --------------------------------------------------------------------------------------------- | | `deposits` | array | Array of deposit objects | | `deposits[].spot_account_id` | string | Spot account ID (UUID) | | `deposits[].asset_symbol` | string | Asset symbol (e.g., "USDT", "BTC") | | `deposits[].amount` | decimal string | Deposit amount | | `deposits[].transaction_hash` | string | On-chain transaction hash | | `deposits[].created_at` | string | Record creation timestamp | | `deposits[].deposited_at` | string | Timestamp when deposit occurred | | `deposits[].chain_id` | integer | Blockchain chain ID where the deposit was received (e.g., 1 for Ethereum, 42161 for Arbitrum) | | `next_cursor` | string | Token to pass as `cursor` for the next page; empty when no more pages | | `has_more` | boolean | Whether another page exists | | `page_size` | integer | Number of deposits per page | **Status Codes**: * `200` - Deposits retrieved successfully * `400` - Missing app\_session\_id parameter * `401` - Authentication failed * `500` - Internal server error ## GET /spot/withdrawals Retrieve spot withdrawal history with cursor pagination. **Authentication:** Required **Pagination:** This endpoint uses cursor-based pagination. See [Pagination](/api-and-programmatic-access/reference#pagination). **Query Parameters**: | Parameter | Type | Required | Options | Description | | ---------------- | ------- | -------- | ----------------------- | --------------------------------------------------------------------------------------------- | | `app_session_id` | string | Yes | — | Spot account app session ID | | `use_cursor` | boolean | No | — | Set `true` to use cursor pagination (use on the first request). | | `cursor` | string | No | — | Opaque continuation token from the previous response's `next_cursor`. Omit on the first page. | | `page_size` | integer | No | default `50`, max `100` | Number of withdrawals per page | **Request** (first page): ```http theme={null} GET /spot/withdrawals?app_session_id=your-session-id&use_cursor=true&page_size=50 ``` **Request** (next page): ```http theme={null} GET /spot/withdrawals?app_session_id=your-session-id&cursor=eyJpZCI6MTB9&page_size=50 ``` **Response**: ```json theme={null} { "withdrawals": [ { "id": "550e8400-e29b-41d4-a716-446655440000", "spot_account_id": "550e8400-e29b-41d4-a716-446655440001", "asset_symbol": "USDT", "amount": "5000.00000000", "status": "completed", "transaction_hash": "0xabcdef1234567890", "failure_reason": "", "requested_at": "2023-12-07T10:30:00.000000Z", "completed_at": "2023-12-07T10:31:00.000000Z", "created_at": "2023-12-07T10:30:01.000000Z", "chain_id": 1 } ], "next_cursor": "eyJpZCI6MTB9", "has_more": true, "page_size": 50 } ``` **Response Fields**: | Field | Type | Description | | -------------------------------- | -------------- | ------------------------------------------------------------------------------------------------ | | `withdrawals` | array | Array of withdrawal objects | | `withdrawals[].id` | string | Withdrawal ID (UUID) | | `withdrawals[].spot_account_id` | string | Spot account ID (UUID) | | `withdrawals[].asset_symbol` | string | Asset symbol (e.g., "USDT", "BTC") | | `withdrawals[].amount` | decimal string | Withdrawal amount | | `withdrawals[].status` | string | Withdrawal status (`pending`, `completed`, `failed`) | | `withdrawals[].transaction_hash` | string | On-chain transaction hash (when completed) | | `withdrawals[].failure_reason` | string | Reason for failure (when status is `failed`) | | `withdrawals[].requested_at` | string | Timestamp when withdrawal was requested | | `withdrawals[].completed_at` | string | Timestamp when withdrawal completed (or failed) | | `withdrawals[].created_at` | string | Record creation timestamp | | `withdrawals[].chain_id` | integer | Blockchain chain ID where the withdrawal was executed (e.g., 1 for Ethereum, 42161 for Arbitrum) | | `next_cursor` | string | Token to pass as `cursor` for the next page; empty when no more pages | | `has_more` | boolean | Whether another page exists | | `page_size` | integer | Number of withdrawals per page | **Status Codes**: * `200` - Withdrawals retrieved successfully * `400` - Missing app\_session\_id parameter * `401` - Authentication failed * `500` - Internal server error ## POST /spot/withdrawal Request a new spot withdrawal. **Authentication:** Required **Known Issue**: Server returns `500` instead of `400` when withdrawal amount exceeds available balance. **Request Body**: ```json theme={null} { "app_session_id": "your-session-id", "asset_symbol": "USDT", "amount": "5000.00000000", "chain_id": 1 } ``` **Request Parameters**: | Parameter | Type | Required | Options | Description | | ---------------- | ------- | -------- | ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `app_session_id` | string | Yes | — | Spot account app session ID | | `asset_symbol` | string | Yes | — | Asset to withdraw (e.g., "USDT", "BTC") | | `amount` | string | Yes | must be positive | Amount to withdraw (decimal format) | | `chain_id` | integer | No | default: server-configured default chain | Target blockchain chain ID for the withdrawal (e.g., 1 for Ethereum, 42161 for Arbitrum). Use `GET /spot/networks` to discover available chains. When omitted, falls back to the server-configured default chain. Returns `400` if omitted and no default is configured. | **Response**: ```json theme={null} { "withdrawal_id": "550e8400-e29b-41d4-a716-446655440000", "status": "pending", "message": "Withdrawal request accepted and funds reserved" } ``` **Response Fields**: | Field | Type | Description | | --------------- | ------ | ------------------------------ | | `withdrawal_id` | string | UUID of the withdrawal request | | `status` | string | Initial status (`pending`) | | `message` | string | Confirmation message | **Status Codes**: * `200` - Withdrawal request accepted * `400` - Invalid request or insufficient funds * `401` - Authentication failed * `500` - Internal server error *** # Trading API Service Source: https://docs.yellow.pro/api-and-programmatic-access/trading-api-service Trading API service: health, fee tiers, and exchange market data. ## Health & System Endpoints ### GET /health Check if the trading API service is running and healthy. **Authentication:** Not required **Response**: ```json theme={null} { "status": "UP" } ``` **Status Codes**: * `200` - Service is healthy * `500` - Service is unhealthy ## Market Data Exchange information (markets, precisions, fees) is available per product at [`GET /spot/exchangeInfo`](/api-and-programmatic-access/spot-trading-api) and [`GET /perpetual/exchangeInfo`](/api-and-programmatic-access/perpetuals-trading-api). ### GET /orderbook Retrieve order book data for a specific trading symbol. **Authentication:** Not required **Query Parameters**: | Parameter | Type | Required | Options | Description | | --------- | ------ | -------- | ------- | ------------------------------------ | | `symbol` | string | Yes | — | Trading symbol to get order book for | **Request**: ```http theme={null} GET /orderbook?symbol=BTCUSD ``` **Response**: ```json theme={null} { "bids": [ ["35000", "1.5"], ["34999", "2.0"] ], "asks": [ ["35001", "1.2"], ["35002", "0.8"] ] } ``` **Response Fields**: | Field | Type | Description | | ------ | ----- | ----------------------------------------------------- | | `bids` | array | Array of bid levels, each containing \[price, amount] | | `asks` | array | Array of ask levels, each containing \[price, amount] | **Status Codes**: * `200` - Order book retrieved successfully * `400` - Missing symbol parameter * `404` - Symbol not found * `500` - Internal server error ### GET /klines Retrieve OHLC/candlestick data for a specific trading symbol. Compatible with Binance API format. **Authentication:** Not required **Query Parameters**: | Parameter | Type | Required | Options | Description | | ----------- | ------- | -------- | ------------------------------------------------------------------------------------------- | ------------------------------------------- | | `symbol` | string | Yes | — | Trading symbol to get klines for | | `interval` | string | No | `1m`, `3m`, `5m`, `15m`, `30m`, `1h`, `2h`, `4h`, `6h`, `8h`, `12h`, `1d`, `3d`, `1w`, `1M` | Kline interval | | `startTime` | integer | No | — | Start time in milliseconds since Unix epoch | | `endTime` | integer | No | — | End time in milliseconds since Unix epoch | | `limit` | integer | No | default `500`, max `1000` | Number of klines to return | | `timeZone` | string | No | — | Timezone offset (e.g., "UTC", "+08:00") | **Request**: ```http theme={null} GET /klines?symbol=BTCUSD&interval=1h&limit=24 ``` **Response**: ```json theme={null} [ [ 1759224600000, "113216.5", "113300.1", "112888", "112945.1", "2602.44", 41934 ] ] ``` **Response Format** (each kline array contains): * `[0]`: Open time (milliseconds) * `[1]`: Open price * `[2]`: High price * `[3]`: Low price * `[4]`: Close price * `[5]`: Volume * `[6]`: Number of trades **Status Codes**: * `200` - Klines retrieved successfully * `400` - Invalid parameters or missing symbol * `404` - Symbol not found * `500` - Internal server error ### GET /ticker/24hr Retrieve 24-hour ticker statistics for a specific trading symbol. **Authentication:** Not required **Query Parameters**: | Parameter | Type | Required | Options | Description | | --------- | ------ | -------- | ------- | -------------------------------- | | `symbol` | string | Yes | — | Trading symbol to get ticker for | **Request**: ```http theme={null} GET /ticker/24hr?symbol=BTCUSD ``` **Response**: ```json theme={null} { "marketId": "BTCUSD", "time": 1759228650754, "min": "111844.3", "max": "114188", "first": "112024.5", "last": "113964.6", "volume": "66457.75557923", "quoteVolume": "7528165635.780153719", "vwap": "113277.4582916087302791", "priceChange": "+1.73%" } ``` **Response Fields**: | Field | Type | Description | | ------------- | -------------- | ------------------------------------------ | | `marketId` | string | Market identifier (e.g., BTCUSD) | | `time` | integer | Timestamp of the data in Unix milliseconds | | `min` | decimal string | Lowest price in the period | | `max` | decimal string | Highest price in the period | | `first` | decimal string | First price in the period (open price) | | `last` | decimal string | Last trade price | | `volume` | decimal string | Total traded volume in the base currency | | `quoteVolume` | decimal string | Total traded volume in the quote currency | | `vwap` | decimal string | Volume-weighted average price | | `priceChange` | string | Price change percentage over the period | **Status Codes**: * `200` - Ticker retrieved successfully * `400` - Missing symbol parameter * `404` - Symbol not found * `500` - Internal server error ## Fees ### GET /account/fee-schedule Retrieve the public fee tier schedule (maker/taker rates per tier, in basis points, and the volume thresholds that qualify for each tier). **Authentication:** Not required **Response**: ```json theme={null} [ { "tier": 0, "spot_maker_bps": "10", "spot_taker_bps": "15", "perp_maker_bps": "2", "perp_taker_bps": "5", "spot_volume_usd_min": "0", "perp_volume_usd_min": "0", "yellow_min": "0" } ] ``` **Response Fields** (array of tiers): | Field | Type | Description | | --------------------- | -------------- | --------------------------------------------------------------- | | `tier` | integer | Tier number (0 is the base tier) | | `spot_maker_bps` | decimal string | Spot maker fee, in basis points | | `spot_taker_bps` | decimal string | Spot taker fee, in basis points | | `perp_maker_bps` | decimal string | Perpetuals maker fee, in basis points | | `perp_taker_bps` | decimal string | Perpetuals taker fee, in basis points | | `spot_volume_usd_min` | decimal string | Minimum 30-day spot volume (USD) to qualify for this tier | | `perp_volume_usd_min` | decimal string | Minimum 30-day perpetuals volume (USD) to qualify for this tier | | `yellow_min` | decimal string | Minimum \$YELLOW balance to qualify for this tier | **Status Codes**: * `200` - Fee schedule retrieved successfully * `502` - Fee service error * `503` - Fee service temporarily unavailable ### GET /account/fee-tier Retrieve the authenticated user's current fee tier and the rates that apply to them. **Authentication:** Required (`read:spot` or `read:futures` scope) **Response**: ```json theme={null} { "fee_tier": 2, "qualifying_track": "volume", "fee_tier_version": 3, "evaluated_at": "2026-06-10T00:00:00Z", "spot_maker_bps": "8", "spot_taker_bps": "12", "perp_maker_bps": "2", "perp_taker_bps": "4", "spot_30d_usd": "1250000", "perp_30d_usd": "5400000", "yellow_balance": "10000" } ``` **Response Fields**: | Field | Type | Description | | ------------------ | -------------- | ---------------------------------------------------- | | `fee_tier` | integer | The user's current tier number | | `qualifying_track` | string | How the tier was reached (e.g. `volume` or `yellow`) | | `fee_tier_version` | integer | Version of the fee schedule used for evaluation | | `evaluated_at` | string | When the tier was last evaluated (RFC3339) | | `spot_maker_bps` | decimal string | Effective spot maker fee, in basis points | | `spot_taker_bps` | decimal string | Effective spot taker fee, in basis points | | `perp_maker_bps` | decimal string | Effective perpetuals maker fee, in basis points | | `perp_taker_bps` | decimal string | Effective perpetuals taker fee, in basis points | | `spot_30d_usd` | decimal string | Trailing 30-day spot volume (USD) | | `perp_30d_usd` | decimal string | Trailing 30-day perpetuals volume (USD) | | `yellow_balance` | decimal string | The user's \$YELLOW balance used for tier evaluation | **Status Codes**: * `200` - Fee tier retrieved successfully * `401` - Authentication failed * `403` - API key does not have the required scope * `404` - No fee tier found for the user * `503` - Fee service temporarily unavailable # WebSocket API Source: https://docs.yellow.pro/api-and-programmatic-access/websocket-api Real-time WebSocket streams for market data, orders, and account updates. The Yellow\.pro WebSocket API provides real-time data streams, order notifications, account updates, and authenticated subscription access. All connections use a single endpoint: ``` wss://trade.api.yellow.pro/ws ``` Both **authenticated** and **unauthenticated** connections are supported. Unauthenticated connections can subscribe to public market data; authenticated connections additionally receive private account, order, and balance notifications. All messages are JSON. ## Connecting Every WebSocket connection — authenticated or not — **must** send a `connect` command immediately after the socket opens. This handshake establishes the session before any subscriptions or notifications are delivered. ### Connection Requirements * **Protocol**: WebSocket (RFC 6455) * **Authentication**: Optional (token-based or header-based) * **Reconnection**: Automatic with exponential backoff (see [Connection management](#connection-management)) * **Message format**: JSON (the server may batch multiple JSON objects per frame, see [Message batching](#message-batching)) ### Connect Handshake (Required) Send an unauthenticated `connect` command right after the socket opens: ```json theme={null} {"id": 1, "connect": {}} ``` **Success response**: ```json theme={null} { "id": 1, "connect": { "client": "3d43bec7-0e0c-429c-a29f-8830bef64437", "data": {}, "ping": 300, "pong": true } } ``` A bare WebSocket connection that does not send the `connect` handshake will be closed by the server with error `3501 (bad request)`. ## Authentication To receive private notifications, authenticate the connection. Two methods are available. Pass your JWT in the `connect` payload after the socket opens. This method works in all environments, including browsers. ```json theme={null} { "id": 1, "connect": { "token": "" } } ``` **Success response** — the server auto-subscribes you to your private channel and includes it in `subs`: ```json theme={null} { "id": 1, "connect": { "client": "3d43bec7-0e0c-429c-a29f-8830bef64437", "data": {}, "subs": { "private.0x1234567890abcdef1234567890abcdef12345678": { "recoverable": true, "epoch": "bQsD", "positioned": true } }, "ping": 300, "pong": true } } ``` Pass the JWT as an `Authorization: Bearer` header when constructing the WebSocket, then still send the `connect` command after the socket opens. ```javascript theme={null} const ws = new WebSocket('wss://trade.api.yellow.pro/ws', [], { headers: { 'Authorization': 'Bearer ' } }); // Still must send the connect command once the connection is open ws.on('open', () => { ws.send(JSON.stringify({ "id": 1, "connect": {} })); }); ``` Custom WebSocket headers only work with Node.js (e.g. the `ws` library). Browser WebSocket APIs do not support custom headers — use the token-based method in browsers. ## Message format All WebSocket messages follow a consistent JSON structure. ### Outbound messages (client → server) ```json theme={null} { "id": 1, "subscribe": { "channel": "channel_name" } } ``` Each outbound command carries a unique, incrementing `id` and a single action object (`connect`, `subscribe`, or `unsubscribe`). ### Inbound messages (server → client) **Response messages** echo the request `id`: ```json theme={null} { "id": 1, "subscribe": {} } ``` **Push notifications** carry no `id` and are wrapped in a `push` envelope: ```json theme={null} { "push": { "channel": "channel_name", "pub": { "data": {} } } } ``` | Field | Type | Description | | --------------- | ------ | --------------------------------------------------- | | `push.channel` | string | Channel the message belongs to | | `push.pub.data` | object | Notification payload (shape depends on the channel) | ### Message batching The server may send multiple JSON objects in a single WebSocket frame, separated by newlines (NDJSON / newline-delimited JSON): ``` {"push":{"channel":"public.tickers.24h","pub":{"data":{}}}} {"push":{"channel":"public.kline.BTCUSD.1m","pub":{"data":{}}}} ``` Calling `JSON.parse(message)` directly on a batched frame throws a `SyntaxError`. Split the frame by newline and parse each line individually: ```javascript theme={null} function parseMessages(raw) { return raw.trim().split('\n') .filter(line => line.trim()) .map(line => JSON.parse(line)); } ``` ## Subscriptions After a successful authenticated handshake, you are **automatically subscribed** to your private notification channel — no explicit subscribe is required. Public channels must be subscribed to explicitly (see [Subscription management](#subscription-management)). ### Private channel name format * **Pattern**: `private.{wallet_address}` * **Example**: `private.0x1234567890abcdef1234567890abcdef12345678` All private notifications (account, order, balance, transfer events) are delivered on this single channel; the event `type` inside `data.header` distinguishes them. ## Private channels Private notifications are pushed on `private.{wallet_address}` for authenticated connections. Each notification carries a `header` with metadata and a `type` identifying the event. ### Perpetuals account update Account-level aggregate metrics for perpetuals (cross-margin). Pushed on balance/position changes (event-triggered) and periodically (timer-driven, default every 3s) for price-driven equity updates. **Notification type**: `perpetuals_account.account_update` ```json theme={null} { "push": { "channel": "private.0x1234567890abcdef1234567890abcdef12345678", "pub": { "data": { "header": { "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "scope": "private", "type": "perpetuals_account.account_update", "user_address": "0x1234567890abcdef1234567890abcdef12345678", "app_session_id": "your-session-id", "created_at": "2025-09-30T15:40:54.455631184Z" }, "id": "550e8400-e29b-41d4-a716-446655440000", "app_session_id": "your-session-id", "owner": "0x1234567890abcdef1234567890abcdef12345678", "state": "active", "total_account_balance": "10000.00000000", "total_unrealized_pnl": "150.00000000", "total_account_equity": "10150.00000000", "total_allocated_margin": "5265.00000000", "total_locked_balance": "5265.00000000", "total_maintenance_margin": "2632.50000000", "available_balance": "4885.00000000", "total_balance_usd": "10150.00000000", "allocated_balance_usd": "5265.00000000", "locked_balance_usd": "5265.00000000", "available_balance_usd": "4885.00000000", "transferable_balances": { "USDT": "3908.00000000" }, "position_modes": { "BTCUSD-PERP": "HEDGE" }, "initial_leverages": { "BTCUSD-PERP": "10" } } } } } ``` | Field | Type | Description | | ------------------------------- | ------ | ----------------------------------------------------------------------------------- | | `data.header` | object | Event metadata (`type`, `user_address`, `app_session_id`, `created_at`) | | `data.id` | string | Perpetuals account ID | | `data.app_session_id` | string | App session ID of the perpetuals account | | `data.owner` | string | Wallet address of the account owner | | `data.state` | string | Account state (`active`, `closing`, `closed`) | | `data.total_account_balance` | string | Total balance across all collateral assets | | `data.total_unrealized_pnl` | string | Sum of unrealized PnL across all positions | | `data.total_account_equity` | string | Total equity (balance + unrealized PnL) | | `data.total_allocated_margin` | string | Total margin allocated to open positions (same value as `total_locked_balance`) | | `data.total_locked_balance` | string | Sum of locked collateral across all assets (orders + position margin) | | `data.total_maintenance_margin` | string | Total maintenance margin required | | `data.available_balance` | string | Account-level balance available for new positions (includes unrealized PnL) | | `data.total_balance_usd` | string | Total balance in stablecoin equivalent; `"0"` when no price | | `data.allocated_balance_usd` | string | Allocated/locked margin in stablecoin equivalent; `"0"` when no price | | `data.locked_balance_usd` | string | Locked balance in stablecoin equivalent; `"0"` when no price | | `data.available_balance_usd` | string | Available balance in stablecoin equivalent; `"0"` when no price | | `data.transferable_balances` | object | Optional. Map of collateral asset → max perp→spot transfer amount (decimal strings) | | `data.position_modes` | object | Optional. Map of market → position mode (`ONE_WAY` or `HEDGE`) | | `data.initial_leverages` | object | Optional. Map of market → leverage string (e.g. `"10"`) | ### Perpetuals balance update Real-time updates on perpetuals account balance changes for a specific collateral asset. **Notification type**: `perpetuals_account.balance_update` ```json theme={null} { "push": { "channel": "private.0x1234567890abcdef1234567890abcdef12345678", "pub": { "data": { "header": { "id": "df444db3-6db8-40e0-9e32-4b499c24d955", "scope": "private", "type": "perpetuals_account.balance_update", "user_address": "0x1234567890abcdef1234567890abcdef12345678", "app_session_id": "your-session-id", "created_at": "2025-09-30T15:40:54.455631184Z" }, "app_session_id": "your-session-id", "owner_address": "0x1234567890abcdef1234567890abcdef12345678", "asset_symbol": "USDT", "total_balance": "10000.00000000", "allocated_balance": "2000.00000000", "locked_balance": "2000.00000000", "available_balance": "8000.00000000", "total_balance_usd": "10000.00000000", "allocated_balance_usd": "2000.00000000", "locked_balance_usd": "2000.00000000", "available_balance_usd": "8000.00000000", "last_updated": "2025-09-30T15:40:54.455631184Z" } } } } ``` | Field | Type | Description | | ---------------------------- | ------ | --------------------------------------------------------------------- | | `data.header` | object | Event metadata | | `data.app_session_id` | string | App session ID of the perpetuals account | | `data.owner_address` | string | Wallet address of the account owner | | `data.asset_symbol` | string | Collateral asset symbol (e.g. `USDT`, `USDC`) | | `data.total_balance` | string | Total balance for this asset | | `data.allocated_balance` | string | Margin allocated to open positions (same value as `locked_balance`) | | `data.locked_balance` | string | Locked collateral for this asset (orders + position margin) | | `data.available_balance` | string | Balance available for new positions (includes unrealized PnL share) | | `data.total_balance_usd` | string | Total balance in stablecoin equivalent; `"0"` when no price | | `data.allocated_balance_usd` | string | Allocated/locked margin in stablecoin equivalent; `"0"` when no price | | `data.locked_balance_usd` | string | Locked collateral in stablecoin equivalent; `"0"` when no price | | `data.available_balance_usd` | string | Available balance in stablecoin equivalent; `"0"` when no price | | `data.last_updated` | string | Last balance update timestamp | ### Perpetuals position update Real-time updates on perpetuals position snapshots (size, margin, leverage-related fields). Pushed on position open and on each fill, and after a successful leverage change for that market (one update per open leg). Not pushed on mark price changes alone. **Notification type**: `perpetuals_account.position_update` ```json theme={null} { "push": { "channel": "private.0x1234567890abcdef1234567890abcdef12345678", "pub": { "data": { "header": { "id": "6c9f53ea-7171-41f8-97c0-119241478703", "scope": "private", "type": "perpetuals_account.position_update", "user_address": "0x1234567890abcdef1234567890abcdef12345678", "app_session_id": "your-session-id", "created_at": "2025-09-30T15:40:54.473694018Z" }, "app_session_id": "your-session-id", "market": "BTCUSD", "direction": "long", "amount": "1.50000000", "entry_price": "35000.00000000", "mark_price": "35100.00000000", "notional_value": "52650.00000000", "leverage": "10.00000000", "unrealized_pnl": "150.00000000", "realized_pnl": "75.00000000", "total_pnl": "225.00000000", "allocated_margin": "5265.00000000", "maintenance_margin": "2632.50000000", "liquidation_price": "31500.00000000", "margin_asset": "USDT" } } } } ``` | Field | Type | Description | | ------------------------- | ------ | -------------------------------------------- | | `data.header` | object | Event metadata | | `data.app_session_id` | string | App session ID of the position | | `data.market` | string | Trading market (e.g. `BTCUSD`) | | `data.direction` | string | Position direction (`long` or `short`) | | `data.amount` | string | Position size (always positive) | | `data.entry_price` | string | Average entry price | | `data.mark_price` | string | Current mark price used for PnL calculation | | `data.notional_value` | string | Current notional value (amount × mark price) | | `data.leverage` | string | Effective leverage | | `data.unrealized_pnl` | string | Current unrealized profit/loss | | `data.realized_pnl` | string | Realized profit/loss from partial closes | | `data.total_pnl` | string | Total profit/loss (unrealized + realized) | | `data.allocated_margin` | string | Margin allocated to this position | | `data.maintenance_margin` | string | Maintenance margin requirement | | `data.liquidation_price` | string | Liquidation price (cross-margin) | | `data.margin_asset` | string | Collateral asset (e.g. `USDT`) | ### Perpetuals funding payment Emitted when a funding settlement is applied to an open position. **Notification type**: `perpetuals_account.funding_payment` ```json theme={null} { "push": { "channel": "private.0x1234567890abcdef1234567890abcdef12345678", "pub": { "data": { "header": { "id": "notif-uuid", "scope": "private", "type": "perpetuals_account.funding_payment", "user_address": "0x1234567890abcdef1234567890abcdef12345678", "app_session_id": "your-session-id", "created_at": "2026-04-29T12:00:00Z" }, "app_session_id": "your-session-id", "owner_address": "0x1234567890abcdef1234567890abcdef12345678", "id": "funding-payment-event-uuid", "market": "BTC-USDT-PERP", "account_id": "550e8400-e29b-41d4-a716-446655440000", "position_id": "660e8400-e29b-41d4-a716-446655440001", "side": "long", "position_size": "0.50000000", "mark_price": "95000.00000000", "funding_rate": "0.00010000", "funding_amount": "-1.25000000" } } } } ``` | Field | Type | Description | | --------------------- | ------ | ----------------------------------------------------------------------------------------------------- | | `data.header` | object | Event metadata | | `data.app_session_id` | string | App session ID | | `data.owner_address` | string | Wallet address of the account owner | | `data.id` | string | Unique ID for this funding payment event | | `data.market` | string | Perpetual market symbol | | `data.account_id` | string | Perpetuals account UUID | | `data.position_id` | string | Position UUID | | `data.side` | string | `long` or `short` | | `data.position_size` | string | Absolute position size at settlement | | `data.mark_price` | string | Mark price used for the payment | | `data.funding_rate` | string | Funding rate applied for the interval | | `data.funding_amount` | string | Signed payment in quote collateral. Positive = debited (you paid); negative = credited (you received) | ### Perpetuals liquidation warning Real-time warning for cross-margin perpetual accounts. Sent when the danger ratio reaches configured thresholds. **Notification type**: `perpetuals_account.liquidation_warning` ```json theme={null} { "push": { "channel": "private.0x1234567890abcdef1234567890abcdef12345678", "pub": { "data": { "header": { "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "scope": "private", "type": "perpetuals_account.liquidation_warning", "user_address": "0x1234567890abcdef1234567890abcdef12345678", "app_session_id": "your-session-id", "created_at": "2026-02-24T10:00:00Z" }, "app_session_id": "your-session-id", "owner": "0x1234567890abcdef1234567890abcdef12345678", "warning_level": "final", "reminder_type": "first_cross", "margin_ratio": "95.0000", "threshold": "95", "triggered_at": "2026-04-06T10:00:00Z", "next_remind_at": "2026-04-06T11:00:00Z" } } } } ``` | Field | Type | Description | | --------------------- | ------ | -------------------------------------------------------------------- | | `data.warning_level` | string | `early` \| `strong` \| `final` | | `data.reminder_type` | string | `first_cross` \| `hourly` | | `data.margin_ratio` | string | Danger ratio percent (`maintenance_margin / equity * 100`) | | `data.threshold` | string | Triggered threshold (`80`, `90`, `95`) | | `data.triggered_at` | string | Current warning trigger time (UTC) | | `data.next_remind_at` | string | Optional. Next planned reminder time, present for `final` level only | **Trigger rules**: * `>= 80%`: triggers once when crossing into this band; resets only after the ratio drops below `75%` * `>= 90%`: triggers once when crossing into this band; resets only after the ratio drops below `85%` * `>= 95%`: crossing can trigger a popup with a minimum `10m` interval between popups; hourly reminders continue while still `>= 95%` * `< 95%`: final-level hourly reminders stop (clear by state/absence; no separate cleared event) * `>= 100%`: no warning popup (liquidation path takes priority) ### Order updates Real-time notifications for order state changes, delivered via two types: `order.updated` and `order.cancelled`. Clients must listen for **both** `order.updated` and `order.cancelled` to receive all order notifications. Spot order notifications identify the order with `order_id`; perpetual order notifications use `uuid`. #### `order.updated` — order state changes Sent when an order is created, partially filled, or fully filled. **Perpetual order example**: ```json theme={null} { "push": { "channel": "private.0x1234567890abcdef1234567890abcdef12345678", "pub": { "data": { "header": { "id": "9db2705e-ba95-4292-8639-f7cd91acc473", "scope": "private", "type": "order.updated", "user_address": "0x1234567890abcdef1234567890abcdef12345678", "app_session_id": "your-session-id", "created_at": "2025-09-30T15:40:54.458854996Z" }, "id": 220507, "uuid": "125a9ddf-bc6b-4f07-82a7-f218d385b8e3", "app_session_id": "your-session-id", "user_address": "0x1234567890abcdef1234567890abcdef12345678", "market": "BTCUSD", "side": "buy", "type": "take_limit", "time_in_force": "gtc", "price": "114280", "trigger_price": "113000", "leverage": "1", "amount": "0", "origin_amount": "0.01", "state": "done", "position_mode": "ONE_WAY", "direction": "long", "reduce_only": false, "created_at": "2025-09-30T15:40:54.455065563Z", "triggered_at": "2025-09-30T15:40:54.456000000Z", "completed_at": "2025-09-30T15:40:54.460000000Z" } } } } ``` **Spot order example**: ```json theme={null} { "push": { "channel": "private.0x1234567890abcdef1234567890abcdef12345678", "pub": { "data": { "header": { "type": "order.updated" }, "order_id": "5d418afd-d0d1-430a-b1b5-4fc98828ce32", "market": "BTCUSD", "side": "buy", "type": "limit", "state": "wait" } } } } ``` | Field | Type | Description | | -------------------- | ------- | ------------------------------------------------------------------------------------------------------ | | `data.header` | object | Event metadata | | `data.id` | number | Order record ID (perpetual orders) | | `data.uuid` | string | Order UUID (perpetual orders only) | | `data.order_id` | string | Order UUID (spot orders only) | | `data.user_address` | string | User's wallet address | | `data.market` | string | Trading market (e.g. `BTCUSD`) | | `data.side` | string | Order side (`buy` or `sell`) | | `data.type` | string | Order type (`limit`, `market`, `take_limit`, `post_only`, etc.) | | `data.time_in_force` | string | Time in force (`gtc`, `ioc`, `fok`) | | `data.price` | string | Execution price | | `data.trigger_price` | string | Trigger price for trigger-originated orders; omitted otherwise | | `data.leverage` | string | Effective leverage (perpetual orders) | | `data.amount` | string | Current order amount | | `data.origin_amount` | string | Original order amount | | `data.state` | string | Order state (`pending`, `wait`, `filled`, `done`, `canceled`) | | `data.position_mode` | string | Position mode for perpetual orders (`ONE_WAY`); omitted for spot | | `data.direction` | string | Position direction for perpetual orders (`long`, `short`, `both`); omitted for spot | | `data.reduce_only` | boolean | `true` = order can only reduce a position (Close); `false` = regular order. Spot orders always `false` | | `data.created_at` | string | Order creation timestamp | | `data.triggered_at` | string | Timestamp when the trigger condition was met (trigger orders only) | | `data.completed_at` | string | Timestamp when the order reached a final state; omitted while still open | #### `order.cancelled` — order cancellation Sent when an order is cancelled. This is a separate event type from `order.updated`. ```json theme={null} { "push": { "channel": "private.0x1234567890abcdef1234567890abcdef12345678", "pub": { "data": { "header": { "type": "order.cancelled" }, "order_id": "5d418afd-d0d1-430a-b1b5-4fc98828ce32", "state": "canceled" } } } } ``` | Field | Type | Description | | ------------------ | ------ | ----------------------------- | | `data.header.type` | string | `"order.cancelled"` | | `data.order_id` | string | Order UUID (spot orders) | | `data.uuid` | string | Order UUID (perpetual orders) | | `data.state` | string | `"canceled"` | ### Order expiration Notification for an expired order. **Notification type**: `order.expired` ```json theme={null} { "push": { "channel": "private.0x1234567890abcdef1234567890abcdef12345678", "pub": { "data": { "header": { "id": "8b8eb153-1acd-4438-b5d2-6d8715b53bb2", "scope": "private", "type": "order.expired", "user_address": "0x1234567890abcdef1234567890abcdef12345678", "app_session_id": "your-session-id", "created_at": "2025-09-30T15:42:43.71880063Z" }, "id": 222488, "uuid": "ad04afd7-e581-4f40-a038-edd14c58c54b", "app_session_id": "your-session-id", "user_address": "0x1234567890abcdef1234567890abcdef12345678", "market": "BTCUSD", "side": "buy", "type": "limit", "time_in_force": "fok", "price": "1", "leverage": "1", "amount": "4037.1", "origin_amount": "4037.1", "state": "expired", "created_at": "2025-09-30T15:42:43.71319921Z" } } } } ``` | Field | Type | Description | | -------------------- | ------ | ---------------------------------- | | `data.header` | object | Event metadata | | `data.id` | number | Order record ID (perpetual orders) | | `data.uuid` | string | Order UUID (perpetual orders) | | `data.market` | string | Trading market | | `data.side` | string | Order side (`buy` or `sell`) | | `data.type` | string | Order type | | `data.time_in_force` | string | Time in force | | `data.price` | string | Order price | | `data.amount` | string | Current order amount | | `data.origin_amount` | string | Original order amount | | `data.state` | string | `"expired"` | | `data.created_at` | string | Order creation timestamp | ### Spot account state update Real-time notification for spot account state changes (opened, closed, etc.). **Notification type**: `spot_account.state_update` ```json theme={null} { "push": { "channel": "private.0x1234567890abcdef1234567890abcdef12345678", "pub": { "data": { "header": { "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "scope": "private", "type": "spot_account.state_update", "user_address": "0x1234567890abcdef1234567890abcdef12345678", "created_at": "2025-10-24T12:00:00.000000000Z" }, "account_id": "550e8400-e29b-41d4-a716-446655440000", "owner_address": "0x1234567890abcdef1234567890abcdef12345678", "app_session_id": "your-session-id", "state": "open" } } } } ``` | Field | Type | Description | | --------------------- | ------ | ----------------------------------- | | `data.header` | object | Event metadata | | `data.account_id` | string | Spot account identifier | | `data.owner_address` | string | Wallet address of the account owner | | `data.app_session_id` | string | Associated app session ID | | `data.state` | string | Account state (`open`, `closed`) | ### Spot balance update Real-time updates on spot account balance changes for a specific asset. Delivered on the `spot_account.balance_update` channel. **Notification type**: `spot_account.balance_update` ```json theme={null} { "push": { "channel": "private.0x1234567890abcdef1234567890abcdef12345678", "pub": { "data": { "header": { "id": "b1c2d3e4-f5a6-7890-bcde-f12345678901", "scope": "private", "type": "spot_account.balance_update", "user_address": "0x1234567890abcdef1234567890abcdef12345678", "created_at": "2025-10-24T12:00:00.000000000Z" }, "app_session_id": "your-session-id", "owner_address": "0x1234567890abcdef1234567890abcdef12345678", "asset_symbol": "USDT", "total_balance": "10000.5000", "available_balance": "9500.5000", "locked_balance": "500.0000", "total_balance_usd": "10000.5000", "available_balance_usd": "9500.5000", "locked_balance_usd": "500.0000", "last_updated": "2025-10-24T12:00:00.000000000Z" } } } } ``` | Field | Type | Description | | ---------------------------- | ------ | --------------------------------------------------------------- | | `data.header` | object | Event metadata | | `data.app_session_id` | string | Associated app session ID | | `data.owner_address` | string | Wallet address of the account owner | | `data.asset_symbol` | string | Asset symbol (e.g. `USDT`, `BTC`, `ETH`) | | `data.total_balance` | string | Total balance for this asset | | `data.available_balance` | string | Available balance for trading/withdrawal | | `data.locked_balance` | string | Balance locked in orders or pending operations | | `data.total_balance_usd` | string | Total balance in stablecoin equivalent; `"0"` when no price | | `data.available_balance_usd` | string | Available balance in stablecoin equivalent; `"0"` when no price | | `data.locked_balance_usd` | string | Locked balance in stablecoin equivalent; `"0"` when no price | | `data.last_updated` | string | Timestamp of last balance update | ### Spot funds deposited Notification when funds are successfully deposited into a spot account. **Notification type**: `spot_account.funds_deposited` ```json theme={null} { "push": { "channel": "private.0x1234567890abcdef1234567890abcdef12345678", "pub": { "data": { "header": { "id": "c1d2e3f4-a5b6-7890-cdef-123456789012", "scope": "private", "type": "spot_account.funds_deposited", "user_address": "0x1234567890abcdef1234567890abcdef12345678", "created_at": "2025-10-24T12:00:00.000000000Z" }, "app_session_id": "your-session-id", "owner_address": "0x1234567890abcdef1234567890abcdef12345678", "asset_symbol": "USDT", "amount": "1000.0000", "transaction_hash": "0xabc123", "deposited_at": "2025-10-24T12:00:00.000000000Z" } } } } ``` | Field | Type | Description | | ----------------------- | ------ | --------------------------------------- | | `data.header` | object | Event metadata | | `data.app_session_id` | string | Associated app session ID | | `data.owner_address` | string | Wallet address of the account owner | | `data.asset_symbol` | string | Deposited asset symbol | | `data.amount` | string | Deposit amount | | `data.transaction_hash` | string | Optional. Transaction hash or reference | | `data.deposited_at` | string | Timestamp when the deposit completed | ### Spot withdrawal accepted Notification when a withdrawal request is accepted and funds are reserved. **Notification type**: `spot_account.withdrawal_accepted` ```json theme={null} { "push": { "channel": "private.0x1234567890abcdef1234567890abcdef12345678", "pub": { "data": { "header": { "id": "d1e2f3a4-b5c6-7890-def1-234567890123", "scope": "private", "type": "spot_account.withdrawal_accepted", "user_address": "0x1234567890abcdef1234567890abcdef12345678", "created_at": "2025-10-24T12:00:00.000000000Z" }, "withdrawal_id": "withdrawal-550e8400-e29b-41d4-a716", "app_session_id": "your-session-id", "owner_address": "0x1234567890abcdef1234567890abcdef12345678", "asset_symbol": "USDT", "amount": "500.0000", "requested_at": "2025-10-24T12:00:00.000000000Z" } } } } ``` | Field | Type | Description | | --------------------- | ------ | ------------------------------------------- | | `data.header` | object | Event metadata | | `data.withdrawal_id` | string | Withdrawal identifier | | `data.app_session_id` | string | Associated app session ID | | `data.owner_address` | string | Wallet address of the account owner | | `data.asset_symbol` | string | Asset being withdrawn | | `data.amount` | string | Withdrawal amount | | `data.requested_at` | string | Timestamp when the withdrawal was requested | ### Spot withdrawal completed Notification when a withdrawal is successfully completed. **Notification type**: `spot_account.withdrawal_completed` ```json theme={null} { "push": { "channel": "private.0x1234567890abcdef1234567890abcdef12345678", "pub": { "data": { "header": { "id": "e1f2a3b4-c5d6-7890-ef12-345678901234", "scope": "private", "type": "spot_account.withdrawal_completed", "user_address": "0x1234567890abcdef1234567890abcdef12345678", "created_at": "2025-10-24T12:05:00.000000000Z" }, "withdrawal_id": "withdrawal-550e8400-e29b-41d4-a716", "app_session_id": "your-session-id", "owner_address": "0x1234567890abcdef1234567890abcdef12345678", "asset_symbol": "USDT", "amount": "500.0000", "transaction_hash": "0xdef456", "completed_at": "2025-10-24T12:05:00.000000000Z" } } } } ``` | Field | Type | Description | | ----------------------- | ------ | --------------------------------------- | | `data.header` | object | Event metadata | | `data.withdrawal_id` | string | Withdrawal identifier | | `data.app_session_id` | string | Associated app session ID | | `data.owner_address` | string | Wallet address of the account owner | | `data.asset_symbol` | string | Asset that was withdrawn | | `data.amount` | string | Withdrawal amount | | `data.transaction_hash` | string | Transaction hash for the withdrawal | | `data.completed_at` | string | Timestamp when the withdrawal completed | ### Spot withdrawal failed Notification when a withdrawal attempt fails and funds are returned to the available balance. **Notification type**: `spot_account.withdrawal_failed` ```json theme={null} { "push": { "channel": "private.0x1234567890abcdef1234567890abcdef12345678", "pub": { "data": { "header": { "id": "f1a2b3c4-d5e6-7890-f123-456789012345", "scope": "private", "type": "spot_account.withdrawal_failed", "user_address": "0x1234567890abcdef1234567890abcdef12345678", "created_at": "2025-10-24T12:05:00.000000000Z" }, "withdrawal_id": "withdrawal-550e8400-e29b-41d4-a716", "app_session_id": "your-session-id", "owner_address": "0x1234567890abcdef1234567890abcdef12345678", "asset_symbol": "USDT", "amount": "500.0000", "failure_reason": "Insufficient liquidity in destination", "failed_at": "2025-10-24T12:05:00.000000000Z" } } } } ``` | Field | Type | Description | | --------------------- | ------ | ------------------------------------ | | `data.header` | object | Event metadata | | `data.withdrawal_id` | string | Withdrawal identifier | | `data.app_session_id` | string | Associated app session ID | | `data.owner_address` | string | Wallet address of the account owner | | `data.asset_symbol` | string | Asset that was attempted | | `data.amount` | string | Withdrawal amount that failed | | `data.failure_reason` | string | Reason for the failure | | `data.failed_at` | string | Timestamp when the withdrawal failed | ### Funds transferred (spot ↔ perpetuals) Real-time notification when funds are transferred between spot and perpetuals accounts. Delivered on the `transfer_updates` channel. The notification is pushed when the transfer reaches a terminal or failure-relevant state. **Notification type**: `account.funds_transferred` ```json theme={null} { "push": { "channel": "transfer_updates", "pub": { "data": { "header": { "id": "f4a5b6c7-d8e9-0123-abcd-456789012345", "scope": "private", "type": "account.funds_transferred", "user_address": "0x1234567890abcdef1234567890abcdef12345678", "app_session_id": "your-session-id", "created_at": "2026-03-09T10:30:00.000000000Z" }, "transfer_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "owner_address": "0x1234567890abcdef1234567890abcdef12345678", "app_session_id": "your-session-id", "source_type": "spot", "dest_type": "perps", "asset_symbol": "USDT", "amount": "500.00000000", "state": "dest_completed", "timestamp": "2026-03-09T10:30:00.000000000Z" } } } } ``` **Failed transfer example**: ```json theme={null} { "push": { "channel": "transfer_updates", "pub": { "data": { "header": { "id": "c0d7b65a-2a25-4f7b-a59a-4ff8b0d2e9d1", "scope": "private", "type": "account.funds_transferred", "user_address": "0x1234567890abcdef1234567890abcdef12345678", "app_session_id": "your-session-id", "created_at": "2026-03-09T10:31:00.000000000Z" }, "transfer_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "owner_address": "0x1234567890abcdef1234567890abcdef12345678", "app_session_id": "your-session-id", "source_type": "spot", "dest_type": "perps", "asset_symbol": "USDT", "amount": "500.00000000", "state": "failed", "failure_stage": "source", "failure_reason": "insufficient balance", "timestamp": "2026-03-09T10:31:00.000000000Z" } } } } ``` | Field | Type | Description | | --------------------- | ------ | -------------------------------------------------------------------------------------------------------- | | `data.header` | object | Event metadata (`app_session_id` is shared between spot and perps accounts) | | `data.transfer_id` | string | Transfer identifier (UUID, idempotency key) | | `data.owner_address` | string | Wallet address of the owner initiating the transfer | | `data.app_session_id` | string | App session ID (shared between the user's spot and perpetuals accounts) | | `data.source_type` | string | Source account type (`spot` or `perps`) | | `data.dest_type` | string | Destination account type (`spot` or `perps`) | | `data.asset_symbol` | string | Asset being transferred (e.g. `USDT`, `USDC`) | | `data.amount` | string | Transfer amount | | `data.state` | string | Transfer state (`dest_completed`, `failed`, `compensation_needed`, `compensated`, `compensation_failed`) | | `data.failure_reason` | string | Optional. Failure reason (failure/compensation states) | | `data.failure_stage` | string | Optional. Which stage failed: `source`, `dest`, or `compensation` | | `data.timestamp` | string | Timestamp for this transfer state change | After a successful transfer you will also receive `spot_account.balance_update` and `perpetuals_account.balance_update` notifications reflecting the updated balances on both sides. ## Public channels Public channels are available to all connections (authenticated or not) and must be subscribed to explicitly. ### Mark price Real-time mark price updates for a market. **Channel pattern**: `public.mark_price.{MARKET}` **Subscribe**: ```json theme={null} { "id": 2, "subscribe": { "channel": "public.mark_price.BTCUSD" } } ``` **Push notification**: ```json theme={null} { "push": { "channel": "public.mark_price.BTCUSD", "pub": { "data": { "header": { "id": "960fcdd0-6f0b-46a5-9647-6297093e168a", "scope": "public", "type": "mark_price", "created_at": "2025-09-30T14:42:52.153092769Z" }, "market": "BTCUSD", "mark_price": "113143.17314493", "index_price": "113143.17314493", "funding_rate": -0.000001, "next_funding_time": "2026-03-16T08:00:00Z" } } } } ``` | Field | Type | Description | | ------------------------ | ------ | ---------------------------------- | | `data.market` | string | Market symbol | | `data.mark_price` | string | Current mark price | | `data.index_price` | string | Current index price | | `data.funding_rate` | number | Current funding rate | | `data.next_funding_time` | string | Next funding settlement time (UTC) | ### Order book (incremental) Real-time order book changes. Subscribing returns an initial snapshot followed by incremental updates. **Channel pattern**: `public.orderbook.increment.{MARKET}` **Subscribe**: ```json theme={null} { "id": 3, "subscribe": { "channel": "public.orderbook.increment.BTCUSD" } } ``` **Initial snapshot response**: ```json theme={null} { "id": 3, "subscribe": { "data": { "header": { "id": "b626d90c-dc5d-4be7-9021-de265ea6764c", "scope": "public", "type": "orderbook.snapshot", "created_at": "2025-09-30T14:42:51.949396721Z" }, "market": "BTCUSD", "sequence_num": 1436308, "bids": [ ["113150", "0.15741658"], ["113140", "0.08147461"] ], "asks": [ ["113170", "0.23884178"], ["113180", "0.21656283"] ] } } } ``` **Incremental update**: ```json theme={null} { "push": { "channel": "public.orderbook.increment.BTCUSD", "pub": { "data": { "header": { "id": "5ee5f313-e5f3-4392-b167-a485481acd6a", "scope": "public", "type": "orderbook.increment", "created_at": "2025-09-30T14:42:52.009378122Z" }, "market": "BTCUSD", "sequence_num": 1436309, "bids": [ ["113140", "0.23295975"] ], "asks": [] } } } } ``` | Field | Type | Description | | ------------------- | ------ | ------------------------------------------------------------- | | `data.market` | string | Trading market symbol | | `data.sequence_num` | number | Monotonically increasing sequence number for ordering updates | | `data.bids` | array | Bid levels `[price, amount]`; empty array means no changes | | `data.asks` | array | Ask levels `[price, amount]`; empty array means no changes | Updates are aggregated within a short window (default 20ms): multiple changes to the same price level within a window are merged into the final state, and clients receive roughly 50 updates per second. A level set to `0` amount has been removed. Sequence numbers stay monotonically increasing — treat any gap as a reason to resubscribe. ### Trade stream (snapshot + increment) Aggregated trade executions for a market. Each subscription receives a snapshot followed by incremental updates with guaranteed sequence continuity. **Channel pattern**: `public.trades.increment.{MARKET}` **Subscribe**: ```json theme={null} { "id": 7, "subscribe": { "channel": "public.trades.increment.BTC-USDT" } } ``` **Snapshot response**: ```json theme={null} { "id": 7, "subscribe": { "data": { "header": { "id": "37521ebc-38fc-4498-83df-e7ffe40f2297", "scope": "public", "type": "trades.snapshot", "created_at": "2025-11-24T02:45:36.441934775Z" }, "market": "BTC-USDT", "sequence_num": 10, "trades": [ { "id": 123455, "price": "67999.80", "amount": "0.0100", "direction": "sell", "executed_at": "2025-11-24T02:45:36.341934775Z" }, { "id": 123456, "price": "68000.25", "amount": "0.0025", "direction": "buy", "executed_at": "2025-11-24T02:45:36.441934775Z" } ] } } } ``` **Incremental update**: ```json theme={null} { "push": { "channel": "public.trades.increment.BTC-USDT", "pub": { "data": { "header": { "id": "2a5084e6-43d0-4a9a-8d7d-95a83827d9c6", "scope": "public", "type": "trades.increment", "created_at": "2025-11-24T02:45:36.491934775Z" }, "market": "BTC-USDT", "sequence_num": 11, "trades": [ { "id": 123457, "price": "68001.10", "amount": "0.0150", "direction": "buy", "executed_at": "2025-11-24T02:45:36.481934775Z" } ] } } } } ``` | Field | Type | Description | | --------------------------- | ------ | -------------------------------------------------------------- | | `data.market` | string | Market symbol (e.g. `BTC-USDT`) | | `data.sequence_num` | number | Monotonically increasing sequence number guaranteeing ordering | | `data.trades` | array | Array of aggregated trade entries | | `data.trades[].id` | number | Monotonic identifier within the aggregation window | | `data.trades[].price` | string | Executed price | | `data.trades[].amount` | string | Executed amount | | `data.trades[].direction` | string | Side of the taker order (`buy` or `sell`) | | `data.trades[].executed_at` | string | ISO 8601 timestamp with microsecond precision | Every subscription starts with a snapshot whose `sequence_num` matches the most recent increment. Sequence numbers are contiguous; if a gap or duplicate is detected, the server rebuilds and broadcasts a fresh snapshot. Treat any missing sequence number as invalid and resubscribe. Default snapshot depth is 50 aggregated entries per market. ### 24h ticker 24-hour ticker statistics for all markets. **Channel**: `public.tickers.24h` **Subscribe**: ```json theme={null} { "id": 4, "subscribe": { "channel": "public.tickers.24h" } } ``` **Push notification**: ```json theme={null} { "push": { "channel": "public.tickers.24h", "pub": { "data": { "header": { "id": "75591ea1-0887-4b3d-8a5d-24400b3fb2ca", "scope": "public", "type": "tickers", "created_at": "2025-09-30T15:37:27.92730374Z" }, "tickers": [ { "market": "BTCUSD", "time": 1759246647916, "min": "113404.5", "max": "114377.2", "first": "113924.9", "last": "114288.3", "volume": "31003.27754213", "quoteVolume": "3534745005.83033429", "vwap": "114011.9782828447619754", "priceChange": "+0.32%" } ] } } } } ``` | Field | Type | Description | | ---------------------------- | ------ | ----------------------------------------- | | `data.tickers[].market` | string | Market symbol | | `data.tickers[].time` | number | Timestamp of the data (Unix milliseconds) | | `data.tickers[].min` | string | 24h lowest price | | `data.tickers[].max` | string | 24h highest price | | `data.tickers[].first` | string | 24h opening price | | `data.tickers[].last` | string | Current/last price | | `data.tickers[].volume` | string | 24h base volume | | `data.tickers[].quoteVolume` | string | 24h quote volume | | `data.tickers[].vwap` | string | Volume-weighted average price | | `data.tickers[].priceChange` | string | 24h price change percentage | ### Kline / candlestick Real-time kline (candlestick) data for a market and interval. **Channel pattern**: `public.kline.{MARKET}.{INTERVAL}` **Available intervals**: `1m`, `3m`, `5m`, `15m`, `30m`, `1h`, `2h`, `4h`, `6h`, `8h`, `12h`, `1d`, `3d`, `1w`, `1M` **Subscribe**: ```json theme={null} { "id": 6, "subscribe": { "channel": "public.kline.BTCUSD.15m" } } ``` **Push notification**: ```json theme={null} { "push": { "channel": "public.kline.BTCUSD.15m", "pub": { "data": { "header": { "id": "1b7a62eb-5f54-4492-a9c4-a7144335d183", "scope": "public", "type": "kline", "created_at": "2025-09-30T14:42:56.947631975Z" }, "market": "BTCUSD", "interval": "15m", "kline": [ 1759242600000, "113044.8", "113225.5", "112978.9", "113137.7", "925.77107192", 39456 ] } } } } ``` The `kline` array is positional: | Index | Type | Description | | ----- | ------ | ------------------------ | | `[0]` | number | Open time (milliseconds) | | `[1]` | string | Open price | | `[2]` | string | High price | | `[3]` | string | Low price | | `[4]` | string | Close price | | `[5]` | string | Volume | | `[6]` | number | Number of trades | ## Subscription management Subscribe to and unsubscribe from channels with `subscribe` / `unsubscribe` commands. Each subscribe/unsubscribe message must use a unique, incrementing `id` (n+1). The `id` lets you match each request to its response. ### Subscribe **Request**: ```json theme={null} { "id": 1, "subscribe": { "channel": "channel_name" } } ``` **Success response**: ```json theme={null} { "id": 1, "subscribe": {} } ``` **Error response**: ```json theme={null} { "id": 1, "subscribe": { "error": { "code": 400, "message": "Invalid channel name" } } } ``` ### Unsubscribe **Request**: ```json theme={null} { "id": 2, "unsubscribe": { "channel": "channel_name" } } ``` **Success response**: ```json theme={null} { "id": 2, "unsubscribe": {} } ``` ## Connection management ### Ping / pong The server sends periodic ping frames to maintain connection health; clients respond with pong frames. * **Ping interval**: 5 minutes * **Pong timeout**: 5 minutes ### Reconnection Implement automatic reconnection with exponential backoff: * **Initial delay**: 1 second * **Maximum delay**: 60 seconds * **Backoff multiplier**: 2 ### Connection recovery The WebSocket API supports recovery on reconnect: * **Message positioning**: resume from the last received message * **Automatic resubscription**: previous subscriptions are restored * **State synchronization**: account state is synchronized on reconnection ## Order placement Placing and canceling orders over WebSocket is not available. Use the REST API instead: * [Spot Trading API](/api-and-programmatic-access/spot-trading-api) * [Perpetuals Trading API](/api-and-programmatic-access/perpetuals-trading-api) Order **notifications** (`order.updated`, `order.cancelled`, `order.expired`) are still delivered over WebSocket on your private channel — see [Order updates](#order-updates). ## Error handling ### Common error codes **Authentication errors**: * `401` — Authentication failed or token invalid * `403` — Insufficient permissions for the requested operation **Subscription errors**: * `400` — Invalid channel name or subscription parameters * `404` — Channel not found or not available * `409` — Already subscribed to the channel ### Error message format All error responses include structured error information: ```json theme={null} { "error": { "code": 400, "message": "Human-readable error description", "details": { "field": "additional_error_context" } } } ``` ## Rate limits WebSocket connections are subject to rate limiting to ensure fair usage: * **Connection limit**: 5 concurrent connections per user * **Subscription limit**: 100 active subscriptions per connection * **Message rate limit**: 100 messages per second per connection Rate limiting violations result in connection termination. # Community Channels Source: https://docs.yellow.pro/community-and-resources/community-channels Join the conversation and connect with other Yellow users and our team on our official community channels. * **X**: [@yellow](https://x.com/yellow) * **Telegram**: [@yellow\_org](https://t.me/yellow_org) * **Discord**: [discord.com/invite/yellownetwork](https://discord.com/invite/yellownetwork) These channels are a great place to: * Ask questions and get help from the community. * Stay up-to-date on the latest news and announcements. * Provide feedback and suggestions for improving the platform. We look forward to seeing you there! # Contact Support Source: https://docs.yellow.pro/community-and-resources/contact-support How to reach Yellow.pro support by email or in-app chat. If you can't find the answer you're looking for in our FAQs and troubleshooting guides, you can reach our support team in one of these ways: * **Email** — send your question to [support@yellow.pro](mailto:support@yellow.pro). * **Chat** — open the support chat on the platform. You can open the chat from: * the **Assets** page, or * the **side menu** on mobile. Our support team is committed to providing timely assistance. We strive to respond to all inquiries within 24 hours. # Overview Source: https://docs.yellow.pro/community-and-resources/overview Connect with the Yellow community and get support. Find official community channels and ways to reach support. Official X, Telegram, and Discord. Reach support by email or chat. # Campaign Hub Source: https://docs.yellow.pro/competitions/campaign-hub The Competition Hub lists every trading competition on Yellow.pro — active, upcoming, and past. Each competition has its own page with its specific dates, prize pool, eligibility, rules, and FAQs. For the rules and mechanics common to all competitions, see **Everything About Competitions on Yellow.pro**. # Everything About Competitions Source: https://docs.yellow.pro/competitions/everything-about-competitions Trading Competitions are time-based events where users compete on trading activity, get ranked on a leaderboard, and top performers earn rewards when the competition ends. This article covers the rules and mechanics common to **every** competition. For dates, prize pools, reward tokens, and other specifics, check that competition's page in the **Competition Hub**. *** ### **Joining** * Join anytime before the competition's end time from the Competitions page. * **Only trades placed after you join count** — tracking starts the moment you join; earlier activity is ignored. * Button shown depends on your status: **Login** (not logged in) → **Deposit** (logged in, no balance in your Trading/Spot Account) → **Join** (logged in, with balance). * Before a competition starts, you can preview the page, reward structure, and countdown, but can't join yet. *** ### **Timeline** Each competition shows a **start time**, **end time**, **countdown**, and **reward structure** — all in **UTC**. * **Before it starts:** countdown shows time remaining until the competition begins. * **Active:** countdown switches to show time remaining until the competition ends; join and trade; leaderboard tracks and updates your position. * **Ended:** no further volume counted, rankings locked, rewards processed. ### What You'll See on the Competition Page Every competition page shows the competition's name, description, and duration; a countdown (to start or end); your join status; prize pool and rewarded ranks; participant count and total volume, alongside your own rank and volume; a leaderboard (rank, trader identifier, volume, reward); and, where applicable, your current tier and the full tier table. While a competition is active, the page reflects it live: * Countdown shows time remaining until the competition ends * Your join status, rank, and volume update as you trade * The leaderboard and live race view update in real time * Your Tier panel reflects your current tier and progress toward the next one Once a competition closes, the page updates to reflect its ended state: * Countdown is replaced with an "ended" message (e.g., competition closed, final rankings being verified, rewards distributed within 7 days) * The leaderboard locks to show final rankings * Your Tier panel shows the tier you finished at Exact panels shown can vary slightly by competition — see that competition's Hub page for what applies there. **Live race view** — opened via a "View race board" button, this shows an animated, real-time visualization of rankings with a live "moves" feed (overtakes, gaps closing, etc.); updates continuously while the competition is active. ### How Volume Is Calculated Volume = **USD-equivalent value** of your trades during the competition, counted from when you join. * **Counts:** fully filled orders (full value); partially filled orders (executed portion only); all eligible markets, unless a competition says otherwise. * **Doesn't count:** cancelled orders; trades before you joined. * **Example:** a $5,000 trade executed during the competition adds $5,000 to your volume. Eligible products/markets (Spot, Perpetual, or both) can vary — check the Hub page. ### Leaderboard Ranks participants by total eligible volume. Refreshes **every 1 minute (UTC)**, so recent trades appear almost in real time, and your rank can shift as others trade. Shows: **identifier** (your external wallet address, or Yellow Wallet address for Google Sign-in users), **volume**, and **current reward allocation** — all subject to change until the competition ends. ### Rewards * Credited automatically to your Trading Account (`Spot Account`) — no manual claim needed. * Distributed within **7 days** after the competition ends. * **Token and structure vary by competition** (e.g., USDT or \$YELLOW; top 10 only vs. top 500) — check the Hub page for exact details. ### Eligibility & Fair Usage * Join any active competition before it ends; participation may be restricted in certain regions per platform policy/regulations. * **Prohibited:** wash trading (fake volume, no real exposure), abusive/coordinated trading, and market manipulation — any of these can mean disqualification or removal from the leaderboard. Enforcement details may vary by competition (see Hub page). *** ### Every Competition Is Different Reward structure, reward token, eligible products/markets, duration, and additional fair-usage rules are set per competition. **Always check that competition's Competition Hub page before participating.** # Yellow Perps Race (Edition II) Source: https://docs.yellow.pro/competitions/yellow-perps-race-edition-ii Trade perps to climb the leaderboard - and unlock lower fees as your volume grows. Top 15 by volume split a 12,500 USDT pool. **Duration:** **Jun 26 → Jul 10, 2026 UTC (2 weeks)** *** ### **Overview**
Prize pool12,500 USDT
Rewarded ranksTop 15 (By Volume)
Eligible productPerpetuals only
Start - EndJun 26 – Jul 10, 2026, UTC
### **Eligibility** * Open to any trader who joins before Jul 10, 2026 UTC. * Only **perpetuals** trading volume counts toward this competition (not Spot). ### **How to Participate** 1. Join the Yellow Perps Race page before it closes. 2. Trade perpetuals - your volume is tracked automatically. 3. Track your rank and reward allocation on the Race page leaderboard. ### **Leaderboard Rules** Ranked by total perpetuals trading volume (USD equivalent) since you joined. ### **Rewards & Distribution** **12,500 USDT prize pool**, split across the top 15 by volume
RankReward
12,750 USDT
22,050 USDT
31,500 USDT
41,180 USDT
5950 USDT
6780 USDT
7650 USDT
8550 USDT
9480 USDT
10400 USDT
11330 USDT
12280 USDT
13240 USDT
14 - 15180 USDT each
*** ### **Trading Fee Discount (Race Tiers)** Joining also unlocks tiered fee discounts on perps, separate from the prize pool: * You always pay whichever is lower - your normal VIP fee or your Race tier fee. Joining never raises your fees. * Climb tiers by trading volume **or** by holding YELLOW - either qualifies. * YELLOW just needs to be in your connected wallet; no deposit required. * Discount applies to both maker and taker fees.
TierVolumeYELLOW heldFees (maker · taker)
Base--0.01% · 0.04%
VIP 1250K6,2000.008% · 0.035%
VIP 21.25M12,4000.006% · 0.03%
VIP 33M27,9000.005% · 0.025%
VIP 45.5M45,0000.004% · 0.02%
VIP 59M65,1000.003% · 0.018%
VIP 613.5M86,8000.002% · 0.015%
*** ### **Terms & Conditions** 1. We track your total trading volume in USD on perpetuals from the moment you join. 2. Scores update every minute and are reflected on the public leaderboard (UTC). 3. USDT prize pool: 12,500 - distributed to the top 15 ranks. 4. Settled within 7 days of close. Wash trading and abusive behaviour will disqualify accounts. ### FAQ's When you join the Race, you'll always pay the lower of the two fees: your Race fee or your current VIP fee. Joining the Race will never increase your trading fees. If your existing VIP fee is already lower, you'll continue using that rate until you reach a Race tier that offers an even better discount. \ \ You can progress through Race fee tiers by either increasing your trading volume or holding more YELLOW tokens - both methods count. Any eligible YELLOW held in your connected wallet is automatically counted, so there's no need to deposit it onto the platform. The applicable discount applies to both maker and taker fees and is available only to users who join the Race. Total perpetuals trading volume in USD, counted from the moment you join. Every minute (UTC). Within 7 days after the competition ends. Yes - your volume counter starts from the moment you join, not from the beginning of the event. Wash trading or abusive behaviour may void your payout at settlement. # FAQ Source: https://docs.yellow.pro/deposits-and-withdrawals/faq Quick answers to common deposit and withdrawal questions on Yellow.pro. Having a problem with a deposit or withdrawal? See [Deposit & Withdrawal Troubleshooting](/deposits-and-withdrawals/troubleshooting) for step-by-step fixes. ## Deposits Deposits are supported on the **Ethereum network only**. Supported assets: ETH, WBTC, USDT, and YELLOW. See [Supported Networks, Assets & Limits](/deposits-and-withdrawals/supported-networks-assets-limits) for confirmations and tracking. Google Sign-in users operate through a Yellow Wallet, so deposits first arrive in Account Balance (`Yellow Wallet`) before being moved to the Trading Account (`Spot Account`). External wallet users skip this — deposits go directly to the Trading Account. See [How to Deposit](/deposits-and-withdrawals/how-to-deposit). No. Deposits go first to Account Balance (Google) or the Trading Account (external wallet). Perpetual trading requires a separate, instant transfer from Trading Account → Perpetual Account. For ERC-20 tokens, **Approval** grants Yellow\.pro permission to access your token (no funds move), while **Deposit** actually transfers the funds. Both are required to complete the deposit. Native ETH deposits only need the Deposit step. See [How to Deposit](/deposits-and-withdrawals/how-to-deposit). Usually minutes, but up to 1 hour during congestion. Deposits require 15 blockchain confirmations before being credited. See [Deposit & Withdrawal Troubleshooting](/deposits-and-withdrawals/troubleshooting). ## Withdrawals It depends on your account type. External wallet users withdraw directly from the Trading Account (`Spot Account`); Google account users must first move funds to Account Balance (`Yellow Wallet`). See [How to Withdraw](/deposits-and-withdrawals/how-to-withdraw). For Google users: (1) transfer Perpetual → Spot (instant), (2) transfer Spot → Account Balance (on-chain, may take time), (3) withdraw from Account Balance. See [How to Withdraw](/deposits-and-withdrawals/how-to-withdraw). Each asset has its own minimum (e.g. USDT 5, ETH 0.005). There's no maximum. See the table in [Supported Networks, Assets & Limits](/deposits-and-withdrawals/supported-networks-assets-limits). Network fees are charged by the blockchain (not Yellow\.pro) and deducted from your withdrawal amount. The estimate is shown before you confirm. See [Supported Networks, Assets & Limits](/deposits-and-withdrawals/supported-networks-assets-limits). Your Account Balance (`Yellow Wallet`) uses smart wallet abstraction, and some platforms don't automatically detect smart wallet balances. Verify the receiving platform supports Ethereum smart contracts before withdrawing. See [How to Withdraw](/deposits-and-withdrawals/how-to-withdraw). # How to Deposit Source: https://docs.yellow.pro/deposits-and-withdrawals/how-to-deposit How to deposit funds on Yellow.pro — the direct flow for external wallets and the two-step flow for Google Sign-in accounts. How you deposit depends on how you signed in. Use the tab that matches your account type. For the supported network, assets, and confirmation requirements, see [Supported Networks, Assets & Limits](/deposits-and-withdrawals/supported-networks-assets-limits). Deposits using an external wallet send funds **directly into your Trading Account (`Spot Account`)**. You do not use Account Balance (`Yellow Wallet`), and no extra transfer step is required before trading. **Before you start** * Your external wallet must be connected to your Yellow\.pro account. * Ensure you have enough balance for the deposit, plus native gas (such as ETH) for the network fee. * Only the Ethereum network is supported. * ERC-20 token deposits may require both an **Approval** and a **Deposit** transaction (see below). * All deposits require **15 blockchain confirmations** before being credited. External Wallet Deposit **Step 1 — Open the Deposit page** 1. Open `yellow.pro/assets/deposit`. 2. Your connected wallet appears automatically under **Select Wallet**. 3. Select the asset under **Select Asset**. 4. Confirm the network (Ethereum). 5. Enter the amount, or click **MAX**. 6. Review the estimated network fee shown below the amount field. **Step 2 — Approve or Deposit** Depending on whether you've previously approved this token, the button shows either **Approve** or **Deposit**. * **Approve** — authorises Yellow\.pro to access the selected token. No funds move. Once confirmed, the button changes to **Deposit**. * **Deposit** — the actual transfer of funds into your Trading Account (`Spot Account`). Confirm it in your wallet. After 15 confirmations, your funds appear and are ready for Spot trading. **To trade Perpetuals,** transfer funds from Trading Account (`Spot Account`) → Perpetual Account on the Assets page (internal, instant). With Google Sign-in, Yellow\.pro creates a Yellow Wallet for you. Deposits arrive first in your **Account Balance (`Yellow Wallet`)** and must then be moved to your Trading Account (`Spot Account`) before trading. **Before you start** * Your deposit address is shown on the Deposit page as both a QR code and a copyable address. * Only the Ethereum network is supported — deposits sent on the wrong network cannot be recovered. * Funds do not go directly to your Trading Account; they arrive in Account Balance first. **Step 1 — Deposit to your Account Balance** 1. Open `yellow.pro/assets/deposit`. 2. Select the asset and confirm the network (Ethereum). 3. Copy your deposit address or scan the QR code. 4. Send funds from your external wallet or exchange to that address. 5. Wait for the transaction to confirm (15 blockchain confirmations). Deposit To Account Balance (Gmail Sign-in) Once confirmed, your funds appear under **Account Balance** on the Assets page. Always confirm the network shown on Yellow\.pro matches the network you're sending from. Deposits sent on the wrong network may not be credited and cannot be reversed. **Step 2 — Move funds to your Trading Account** Account Balance To Trading (Spot) Account Transfer 1. Open `yellow.pro/assets`. 2. Click **Transfer**. 3. Select **Account Balance** as the source and **Trading Account (`Spot Account`)** as the destination. 4. Choose the asset and amount, then confirm. Once completed, your funds are available for trading. **To trade Perpetuals,** transfer again from Trading Account → Perpetual Account (internal, instant). Trading (Spot) Account To Perpetual Account Transfer ## Understanding Approval vs Deposit Transactions When depositing ERC-20 tokens such as USDT or WBTC from an external wallet, you may be asked for two separate wallet confirmations. They serve different purposes: | | Approval | Deposit | | ---------------------------------- | --------------------------------- | ------------------------------------ | | Purpose | Grants token access permission | Transfers funds into Trading Account | | Do funds move? | No | Yes | | Always required? | Only if no active approval exists | Yes | | Deposit completed after this step? | No | Yes | * If only the **Approval** is completed, your funds stay in your wallet — return to the Deposit page and complete the **Deposit** transaction. * If you've previously approved a token and the approval is still active, the Approval step is skipped. * **Native ETH deposits don't require an Approval** — only the Deposit transaction. ## Why Google Sign-in Uses a Two-Step Flow Google Sign-in users operate through a smart contract wallet (the Yellow Wallet). Deposits arrive there first as **Account Balance (`Yellow Wallet`)** — stored securely but not yet tradable — and must be transferred to the **Trading Account (`Spot Account`)** before Spot trading. This gives clear visibility of where funds are, and lets the Yellow Wallet be managed independently on Yellow\.com. External wallet users skip this step entirely. See [Understanding Your Balances](/account-and-balance/understanding-your-balances) for the full model. ## Related Articles * [Supported Networks, Assets & Limits](/deposits-and-withdrawals/supported-networks-assets-limits) * [How to Transfer Funds Between Accounts](/account-and-balance/transfer-funds-between-accounts) * [Deposit & Withdrawal Troubleshooting](/deposits-and-withdrawals/troubleshooting) # How to Withdraw Source: https://docs.yellow.pro/deposits-and-withdrawals/how-to-withdraw How to withdraw funds on Yellow.pro — directly from your Trading Account (external wallet) or via Account Balance (Google Sign-in). How you withdraw depends on how you signed in. Use the tab that matches your account type. Before withdrawing, review [Supported Networks, Assets & Limits](/deposits-and-withdrawals/supported-networks-assets-limits) for the supported network, minimum amounts, network fees, and the rule that **withdrawals are final and cannot be reversed**. External wallet users withdraw funds **directly from the Trading Account (`Spot Account`)** to their connected wallet. No Account Balance step is involved. Withdrawal via External Wallet **Prerequisites** * Your external wallet is connected. * Funds are available in your Trading Account (`Spot Account`) and not locked in open orders, positions, or margin. * If funds are in the Perpetual Account, transfer them to the Trading Account first (see below). **Steps** 1. Open `yellow.pro/assets/withdraw`. 2. Your connected wallet and network are selected automatically. 3. Select the asset. 4. Enter the amount. 5. Review the estimated network fee and final amount received. 6. Click **Withdraw** to submit. No recipient address entry is required — your connected wallet is used automatically. **If funds are in the Perpetual Account:** open `yellow.pro/assets/perps`, click **Transfer**, move funds Perpetual Account → Spot Account (instant), then return to the Withdraw page. Google account users withdraw from their **Account Balance (`Yellow Wallet`)**. Funds must reach Account Balance before an on-chain withdrawal can be executed, and you enter the recipient address manually. **Prerequisites** * Funds must be in your Account Balance (`Yellow Wallet`) to initiate withdrawal. * If funds are in the Perpetual Account → transfer to Trading Account (`Spot Account`) first. * If funds are in the Trading Account → transfer to Account Balance (`Yellow Wallet`) first. * Funds are not locked in open orders, positions, or margin. **Prepare your funds (if needed)** 1. **Perpetual → Spot:** open `yellow.pro/assets/perps`, click **Transfer**, move Perpetual Account → Spot Account (instant). 2. **Spot → Account Balance:** open `yellow.pro/assets`, click **Transfer**, move Trading Account (`Spot Account`) → Account Balance (`Yellow Wallet`) (on-chain, may take time). Wait for it to complete. Perpetual Account To Trading (Spot) Account To Account Balance Transfer **Steps** 1. Open `yellow.pro/assets/withdraw`. 2. Enter the recipient's external wallet address (any wallet on the Ethereum network). 3. Select the asset. 4. Enter the amount. 5. Review the estimated network fee and final amount received. 6. Click **Withdraw** to submit. Withdraw To External Wallet From Account Balance Your Account Balance uses smart wallet abstraction. Some receiving platforms don't automatically detect smart wallet balances. Verify the receiving platform is compatible with Ethereum smart contracts before withdrawing. ## Processing Time Most withdrawals complete within a few minutes. During Ethereum network congestion, processing may take up to 1 hour or longer. Track your status — including TxID, network fee, and final amount — at `yellow.pro/assets/history`. ## Related Articles * [Supported Networks, Assets & Limits](/deposits-and-withdrawals/supported-networks-assets-limits) * [How to Transfer Funds Between Accounts](/account-and-balance/transfer-funds-between-accounts) * [Deposit & Withdrawal Troubleshooting](/deposits-and-withdrawals/troubleshooting) # Overview Source: https://docs.yellow.pro/deposits-and-withdrawals/overview Add funds to your account and withdraw them to your wallet. Everything you need to fund your account and withdraw your assets. Deposit via external wallet or Google. Withdraw to your wallet. Network, assets, minimums, and fees. Resolve common deposit and withdrawal issues. Quick answers about deposits and withdrawals. # Supported Networks, Assets & Limits Source: https://docs.yellow.pro/deposits-and-withdrawals/supported-networks-assets-limits Supported network and assets, blockchain confirmations, minimum withdrawal amounts, network fees, and irreversibility rules for deposits and withdrawals. This page covers everything that applies to both deposits and withdrawals: the supported network, assets, confirmation requirements, minimum withdrawal amounts, network fees, and the rules around irreversibility. ## Supported Network **Ethereum is the only network currently supported** for deposits and withdrawals on Yellow\.pro. All transactions are processed through the Ethereum blockchain. Funds sent on any other network will not be credited and **cannot be recovered** by the platform. Always confirm the selected network matches your sending or receiving wallet before confirming. ## Supported Assets All assets are ERC-20 tokens on **Ethereum mainnet**. Always verify the token's contract address before depositing — depositing a different token to a Yellow\.pro address may be unrecoverable. | Asset | Name | Contract address (Ethereum) | Minimum Withdrawal | | ------ | -------------------- | -------------------------------------------- | ------------------ | | ETH | Ether (native token) | Native — no contract address | 0.005 | | WBTC | Wrapped Bitcoin | `0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599` | 0.00015 | | USDT | Tether | `0xdAC17F958D2ee523a2206206994597C13D831ec7` | 5 | | YELLOW | Platform token | `0x236eB848C95b231299B4AA9f56c73D6893462720` | 1,000 | | WSOL | Wrapped SOL | `0xD31a59c85aE9D8edEFeC411D448f90841571b89c` | 0.1 | | BNB | BNB | `0xB8c77482e45F1F44dE1745F52C74426C631bDD52` | 0.015 | When depositing, select the asset from the deposit form — the network is automatically set to Ethereum. Always confirm the asset and network before sending funds. You can deposit and withdraw all assets above, but not every asset has a spot trading pair yet. **WSOL** and **BNB** are currently deposit-and-withdraw only. See [Market Rules & Limits](/spot-trading/market-rules) for the markets available to trade. ## Blockchain Confirmations Deposits require **15 blockchain confirmations** before being credited to your account. This helps ensure transaction security and finality on the Ethereum network. During periods of high network congestion, confirmations may take longer than usual. ## Minimum Withdrawal Amounts Withdrawals below the minimum amount cannot be initiated. If your available balance is below the required minimum for an asset (see the table above), the withdrawal option remains unavailable until you have more funds. There is **no maximum** withdrawal limit. ## Network Fees Withdrawals incur an Ethereum network fee — a blockchain transaction cost, not a Yellow\.pro fee — that is deducted from your withdrawal amount and shown on the Withdraw page before you confirm. For why it applies, why it changes, and how it's deducted, see [Withdrawal Network Fees Explained](/fees/withdrawal-network-fees). ## Withdrawals Are Final Once a withdrawal is submitted on-chain, it **cannot be reversed, cancelled, or modified.** Funds sent to the wrong address, or to an unsupported blockchain, cannot be recovered by Yellow\.pro. Always verify the recipient address and that the receiving platform supports the Ethereum network before confirming. ## Tracking Deposits & Withdrawals Track transaction status and details in your history at `yellow.pro/assets/history` — including the TxID, asset and amount, network fee deducted, final received amount, and status. For deposits to a Google Sign-in Account Balance, you can also verify the on-chain transaction on a blockchain explorer such as `etherscan.io` using your deposit address. ## Related Articles * [How to Deposit](/deposits-and-withdrawals/how-to-deposit) * [How to Withdraw](/deposits-and-withdrawals/how-to-withdraw) * [Deposit & Withdrawal Troubleshooting](/deposits-and-withdrawals/troubleshooting) # Deposit & Withdrawal Troubleshooting Source: https://docs.yellow.pro/deposits-and-withdrawals/troubleshooting Identify and resolve common deposit and withdrawal issues before contacting support. Use this guide to diagnose common deposit and withdrawal issues. For network, asset, limit, and irreversibility rules, see [Supported Networks, Assets & Limits](/deposits-and-withdrawals/supported-networks-assets-limits). * **External wallet, ERC-20 token:** make sure you completed **both** the Approval and the Deposit transaction. Approval only grants permission — if the Deposit step wasn't confirmed, funds stay in your wallet. Return to the Deposit page and check whether the button shows **Deposit**. * **Google Sign-in:** deposits first appear in **Account Balance (`Yellow Wallet`)**, not the Trading Account. Open the Assets page; if the funds are there, transfer them to the Trading Account (`Spot Account`) before trading. This is expected for Google Sign-in users — deposits arrive in Account Balance (`Yellow Wallet`) first. Open the Assets page, click **Transfer**, and move funds from Account Balance → Trading Account (`Spot Account`). See [How to Transfer Funds Between Accounts](/account-and-balance/transfer-funds-between-accounts). During congestion, deposits can take longer. Check status on a blockchain explorer (`etherscan.io`) using your deposit address or sending wallet address, or on the Deposit History page (`yellow.pro/assets/history`). Deposits need 15 confirmations. If it still hasn't reflected after the expected time, contact support with your transaction hash, wallet address, token, and amount. Deposits sent on an unsupported network or to an incorrect address cannot be credited or recovered. Only Ethereum is supported. Always copy the deposit address directly from the Deposit page and confirm the network before sending. The funds were not transferred and remain in your wallet. Retry from the Deposit page. For ETH, no Approval is required — just retry the Deposit transaction. Possible causes: funds aren't in the correct account (External → Trading Account; Google → Account Balance), available balance is reduced by open orders or positions, required transfers aren't complete, or the amount is below the minimum. Verify fund location, close restricting orders/positions, complete required transfers, and check the [minimum amounts](/deposits-and-withdrawals/supported-networks-assets-limits). Your available balance is likely reduced by funds locked in open orders or active perpetual positions, funds not yet in the correct account, or funds still processing during a transfer. Close or adjust trading activity and confirm fund location for your account type. Usually Ethereum network congestion or normal confirmation time (minutes, up to \~1 hour). Check status with your TxID at `yellow.pro/assets/history`. If not completed after 1 hour, contact support with your TxID. The transaction may still be processing on the receiving side, or the receiving platform has its own delays. Check your TxID at `yellow.pro/assets/history`, wait for confirmations, and contact the receiving wallet or exchange with your TxID. Blockchain transactions are irreversible. Funds sent to an incorrect address or unsupported network may not be recoverable — especially if the receiving platform doesn't support smart wallet abstraction. Contact the receiving platform with your TxID. Yellow\.pro supports Ethereum only. The Ethereum network fee is deducted from the withdrawal amount. Compare the withdrawal amount, network fee, and final received amount in your history. Fees are shown before you confirm. ## Contacting Support When reporting a deposit or withdrawal issue, include your Yellow\.pro wallet address, external wallet address (if applicable), transaction hash (TxID), token and network, amount, and a brief description (a screenshot helps). This lets the team investigate faster. See [Contact Support](/community-and-resources/contact-support). # FAQ Source: https://docs.yellow.pro/fees/faq Quick answers about trading fees, VIP tiers, $YELLOW, funding, and network fees. ## Trading Fees Trading fees depend on your VIP tier and whether your order is maker or taker. Base tier is Spot 0.08% maker / 0.10% taker and Perp 0.01% maker / 0.04% taker. See [VIP Tiers & Fee Discounts](/fees/vip-tiers) for the complete schedule. Maker orders add liquidity and have lower fees; taker orders consume liquidity and have higher fees. Market orders are usually taker; limit orders can be either. See [Trading Fees (Maker & Taker)](/fees/trading-fees). Fees are charged whenever an order is successfully filled: `Fee = Fill Value × Fee Rate` (Fill Value = Price × Size). Cancelled or unfilled orders generate no fees. See [Trading Fees (Maker & Taker)](/fees/trading-fees). It depends on the market. On **Spot**, the fee is taken in the asset you **receive** — the base asset when you buy, the quote asset when you sell. On **Perpetuals**, fees are charged in the **quote currency** (e.g. USDT). See [Trading Fees (Maker & Taker)](/fees/trading-fees). View fees in your trade history (`yellow.pro/spot/orders?tab=trades` or `/perps/orders?tab=trades`). To reduce them, increase your VIP tier through trading volume or by holding \$YELLOW. See [VIP Tiers & Fee Discounts](/fees/vip-tiers). ## VIP Tiers & \$YELLOW Your VIP tier determines your trading fees — higher tiers pay less. It's evaluated automatically and continuously as your trading activity or \$YELLOW balance changes, and you're always placed in the highest tier you qualify for. See [VIP Tiers & Fee Discounts](/fees/vip-tiers). Meet any one requirement: 30-day Spot volume, 30-day Perpetual volume, or a 24-hour average $YELLOW balance in your Trading Account (`Spot Account`). VIP 1 needs 100K USDT Spot volume, 1M USDT Perp volume, or 10,000 $YELLOW. See [VIP Tiers & Fee Discounts](/fees/vip-tiers). Hold a 24-hour average of $YELLOW in your Trading Account (`Spot Account`) to qualify for higher VIP tiers. Only Trading Account balance counts — not Account Balance (`Yellow Wallet`) or external wallets. There's no separate discount for paying fees with $YELLOW. See [\$YELLOW Token & Fee Discounts](/fees/yellow-token-fee-discount). $YELLOW is currently available directly on Yellow.pro for trading and holding. Additional exchange listings may be added in the future. See [$YELLOW Token & Fee Discounts]\(/fees/yellow-token-fee-discount). ## Funding Fees Funding fees are payments exchanged between long and short traders every 8 hours on Perpetual markets (positive rate: longs pay shorts; negative: shorts pay longs). They only apply if you hold an open position at the funding timestamp. See [Funding Fees Explained](/fees/funding-fees-explained). Yes. Trading fees are charged when orders fill; funding fees are exchanged every 8 hours between traders for open Perpetual positions and are not collected by Yellow\.pro. See [Funding Fees Explained](/fees/funding-fees-explained). ## Network Fees They're Ethereum blockchain transaction fees required to process withdrawals on-chain — not Yellow\.pro fees. They vary with network congestion, and Yellow\.pro shows the estimate before you confirm. See [Withdrawal Network Fees Explained](/fees/withdrawal-network-fees). The network fee is deducted from your withdrawal — e.g. a 100 USDT withdrawal with a 1 USDT fee results in 99 USDT received. See [Withdrawal Network Fees Explained](/fees/withdrawal-network-fees). ## Fee Split Your fee is divided internally — 85% toward \$YELLOW buybacks and 15% toward platform operations. The split does **not** increase your fee — the amount you pay is unchanged. See [Fee Split Explained](/fees/fee-split). Besides trading fees, Spot has no additional fees. Perpetual traders also pay funding fees (every 8 hours). Network fees apply to deposits and withdrawals. # Fee Split Explained Source: https://docs.yellow.pro/fees/fee-split How every trading fee collected on Yellow.pro is divided internally between $YELLOW buybacks and platform operations. Every trading fee collected on Yellow\.pro is automatically divided into allocation buckets that support \$YELLOW buybacks and platform operations. The trading fee **you** pay does not change. The fee split only determines how the collected fee is distributed internally after your trade completes. ## Fee Split * **85%** → \$YELLOW buybacks * **15%** → platform operations The buyback allocation is the largest portion. ## What Each Allocation Does * \*\*$YELLOW buyback (85%)** — purchases $YELLOW from the open market, connecting platform trading activity to the token's value and ecosystem strength. * **Platform operations (15%)** — infrastructure, development, and operational costs. ## Example A trade generating a 10 USDT trading fee is divided as **8.5 USDT → \$YELLOW buybacks** and **1.5 USDT → platform operations**. The trader paid exactly 10 USDT — only the internal use differs. ## Important Things to Know * The trading fee you pay stays exactly the same — splitting happens internally. * The majority of collected fees go toward \$YELLOW buybacks. * Split percentages may evolve as the platform develops. ## Related Articles * [Trading Fees (Maker & Taker)](/fees/trading-fees) * [\$YELLOW Token & Fee Discounts](/fees/yellow-token-fee-discount) * [VIP Tiers & Fee Discounts](/fees/vip-tiers) # Funding Fees Explained Source: https://docs.yellow.pro/fees/funding-fees-explained What funding fees are, when they're charged, and how funding rates work on Yellow.pro perpetual markets. Funding fees apply **only to Perpetual trading** and are separate from trading fees. Funding keeps perpetual contract prices close to the underlying market price, and is **exchanged directly between traders** — Yellow\.pro does not collect it. ## What Is a Funding Fee? A payment exchanged between long and short traders, depending on the funding rate: * **Positive rate:** long positions pay short positions. * **Negative rate:** short positions pay long positions. ## When Funding Is Charged Funding is usually exchanged **every 8 hours** (the interval may be shorter for highly volatile tokens). It only applies if you hold an open position **at the funding timestamp** — close before funding and no fee is exchanged. ## How Funding Rates Work Rates are dynamic and change continuously based on market demand, the long/short imbalance, and the difference between the perpetual price and the spot price. `Funding Fee = Position Value × Funding Rate`. > **Long pays (positive rate):** a 10,000 USDT long at +0.01% pays 10,000 × 0.0001 = **1 USDT** to shorts. **Short pays (negative rate):** a 10,000 USDT short at −0.01% pays **1 USDT** to longs. ## Where to Check Funding The Perpetual trading page shows the current funding rate, the next funding countdown, who pays at the next timestamp, and previous rates. Funding history is under the Transaction History section on the Perpetual trading page. ## Important Things to Know * Funding applies **only to Perpetual trading** — Spot does not use funding. * Funding is **different** from trading fees and blockchain network fees. * Funding is exchanged **between traders**, not collected by Yellow\.pro. * Your position must be open at the funding timestamp to pay or receive funding. ## Related Articles * [Trading Fees (Maker & Taker)](/fees/trading-fees) * [What is Perpetual Trading?](/perpetual-trading/what-is-perpetual-trading) # Overview Source: https://docs.yellow.pro/fees/overview Trading fees, VIP tiers, funding, network fees, and the $YELLOW token. Understand every fee on Yellow\.pro and how to reduce yours. How trading fees are calculated. The full fee schedule by tier. Perpetual funding payments. Blockchain network fees. Hold \$YELLOW for lower fees. How collected fees are allocated. Quick answers about fees. # Trading Fees (Maker & Taker) Source: https://docs.yellow.pro/fees/trading-fees How trading fees work on Yellow.pro for Spot and Perpetuals, and the difference between maker and taker orders. Yellow\.pro charges a trading fee when your order is **filled** on a Spot or Perpetual market. The amount depends on your [VIP tier](/fees/vip-tiers) and whether your order acts as a maker or taker. ## How Trading Fees Are Calculated `Fee = Fill Value × Fee Rate`, where `Fill Value = Price × Size`. > **Example:** buy 1 ETH at 2,000 USDT with a 0.1% taker fee → Fill Value = 2,000 USDT, Fee = 2,000 × 0.001 = **2 USDT**. Fees are charged **only on filled orders** — cancelled or unfilled orders cost nothing, and partial fills are charged only on the filled portion. The fee currency differs by market: * **Spot** — charged in the asset you **receive**: the base asset when you buy (e.g. ETH on an `ETH-USDT` buy), the quote asset when you sell (e.g. USDT on an `ETH-USDT` sell). * **Perpetuals** — charged in the **quote currency** (e.g. USDT). ## Maker vs Taker Your rate depends on whether your order adds or removes liquidity: * **Maker** — adds liquidity by resting in the order book (e.g. a limit buy below the market, or a limit sell above it). **Lower fee.** * **Taker** — removes liquidity by filling immediately against existing orders (market orders, or limit orders that match an existing price). **Slightly higher fee.** Order type doesn't always decide this: a limit order placed away from the market is usually a maker, but a limit order placed at a matching price fills instantly as a taker. At higher VIP tiers, Perpetual maker fees fall — reaching **0%** at VIP 4 and above. See [VIP Tiers & Fee Discounts](/fees/vip-tiers). ## Spot vs Perpetual Spot trading has slightly higher fees than Perpetual trading. Your exact maker and taker rates on both markets are set by your **VIP tier** — see the full schedule in [VIP Tiers & Fee Discounts](/fees/vip-tiers). ## Important Things to Know * **Funding fees are separate** — Perpetual traders also pay [funding fees](/fees/funding-fees-explained) (every 8 hours). * **Your VIP tier updates automatically** as your trading activity or \$YELLOW balance changes. * \*\*No separate $YELLOW discount** — your savings come from your VIP tier, not from paying fees with $YELLOW. See [\$YELLOW Token & Fee Discounts](/fees/yellow-token-fee-discount). * The fee you pay is divided internally afterwards — see [Fee Split Explained](/fees/fee-split). ## Where to Check Your Fees View exact fees in your trade history — Spot at `yellow.pro/spot/orders?tab=trades`, Perpetual at `yellow.pro/perps/orders?tab=trades`. Each trade shows the fee type (maker or taker), the amount charged, and the executed price and size. ## Related Articles * [VIP Tiers & Fee Discounts](/fees/vip-tiers) * [Funding Fees Explained](/fees/funding-fees-explained) * [Fee Split Explained](/fees/fee-split) # VIP Tiers & Fee Discounts Source: https://docs.yellow.pro/fees/vip-tiers How VIP tiers determine your trading fees on Yellow.pro, how to qualify, and the complete fee schedule by tier. Your **VIP tier** determines your trading fees — higher tiers receive lower maker and taker fees on both Spot and Perpetual markets. Your tier is evaluated automatically and updates continuously. ## How to Qualify Qualify for a higher tier by meeting **any one** of these (whichever gets you highest): * 30-day **Spot** trading volume * 30-day **Perpetual** trading volume * 24-hour average **\$YELLOW** balance held in your Trading Account (`Spot Account`) For $YELLOW qualification, only your **24-hour average** balance in the **Trading Account (`Spot Account`)** counts — not your current balance, and not $YELLOW in Account Balance (`Yellow Wallet`) or external wallets. ## Complete VIP Fee Schedule | Tier | Spot Maker | Spot Taker | Perp Maker | Perp Taker | 30d Spot Vol | 30d Perp Vol | \$YELLOW Balance | | ----- | ---------- | ---------- | ---------- | ---------- | ------------ | ------------ | ---------------- | | Base | 0.08% | 0.10% | 0.01% | 0.04% | — | — | — | | VIP 1 | 0.06% | 0.08% | 0.008% | 0.035% | 100K | 1M | 10,000 | | VIP 2 | 0.05% | 0.07% | 0.005% | 0.03% | 500K | 5M | 50,000 | | VIP 3 | 0.04% | 0.055% | 0.002% | 0.025% | 2.5M | 25M | 350K | | VIP 4 | 0.03% | 0.045% | 0% | 0.02% | 10M | 100M | 2M | | VIP 5 | 0.02% | 0.035% | 0% | 0.015% | 50M | 500M | 5M | | VIP 6 | 0.015% | 0.03% | 0% | 0.01% | 200M | 2B | 20M | Volumes are in USDT. \$YELLOW balance is the 24-hour average required in your Trading Account. ## Zero Perpetual Maker Fees (VIP 4+) From **VIP 4**, Perpetual maker orders charge **0%** — no maker fee on perpetual markets. This is one of the highest benefits for active perpetual traders. ## How Your Tier Is Evaluated You're placed in the highest tier any single metric qualifies for. For example, 2.5M USDT of 30-day Spot volume qualifies for VIP 3, even if your \$YELLOW balance alone would only reach VIP 1. The platform continuously re-evaluates and adjusts your tier; if you no longer meet a tier's requirements, you drop to the highest tier you still qualify for. To see your current tier and progress, open your account settings or trading dashboard and look for "VIP Tier" or "Fee Status." ## Related Articles * [Trading Fees (Maker & Taker)](/fees/trading-fees) * [\$YELLOW Token & Fee Discounts](/fees/yellow-token-fee-discount) * [Fee Split Explained](/fees/fee-split) # Withdrawal Network Fees Explained Source: https://docs.yellow.pro/fees/withdrawal-network-fees Why a blockchain network fee applies to withdrawals, why it changes, and how it's deducted from your withdrawal amount. When withdrawing from Yellow\.pro, a blockchain **network fee** may apply. This is **not charged by Yellow\.pro** — it's a blockchain transaction cost to process and confirm the withdrawal on-chain. All withdrawals are currently processed through the **Ethereum network**. ## Why Network Fees Exist Blockchain transactions require validators to process and confirm them. The network fee pays for this processing — it's a standard blockchain cost, not a Yellow\.pro fee. ## Why Network Fees Change Network fees are dynamic and rise or fall with Ethereum activity. During congestion they can be higher than usual; when activity is lower they decrease. The estimated fee shown before confirmation may therefore change over time. > **Example:** withdraw 100 USDT with a 1 USDT network fee → final received amount is **99 USDT**. The fee is deducted from your withdrawal and sent to the network. ## Where to Check Before confirming, Yellow\.pro shows the selected network (currently Ethereum only), the estimated network fee, and the final amount you'll receive. You can review the actual fee afterwards in your withdrawal history and on a blockchain explorer like Etherscan. ## Important Things to Know * Withdrawal network fees are **blockchain fees**, not Yellow\.pro trading fees. * They **change** with Ethereum congestion. * Withdrawals are **Ethereum only** — sending to unsupported networks may cause permanent loss. * The final received amount is **lower** after the network fee. * Once submitted on-chain, a withdrawal **cannot be reversed** — always verify the address and network. ## Related Articles * [How to Withdraw](/deposits-and-withdrawals/how-to-withdraw) * [Supported Networks, Assets & Limits](/deposits-and-withdrawals/supported-networks-assets-limits) # $YELLOW Token & Fee Discounts Source: https://docs.yellow.pro/fees/yellow-token-fee-discount What the $YELLOW token is and how holding it qualifies you for higher VIP tiers and lower trading fees on Yellow.pro. \$YELLOW is the native platform token of Yellow\.pro. It can be held, traded, and used for platform utilities such as VIP tier qualification and reduced trading fees. ## What \$YELLOW Can Be Used For * Qualifying for higher [VIP tiers](/fees/vip-tiers) (and lower trading fees) * Trading on Yellow\.pro * Holding within your Trading Account (`Spot Account`) More utilities may be introduced as the platform develops. ## How Fee Discounts Work Holding \$YELLOW helps you qualify for higher VIP tiers, which give lower fees across Spot and Perpetual markets. The only fee benefit of $YELLOW is **VIP tier qualification**. There is **no separate discount** for paying trading fees with $YELLOW — your savings come entirely from your VIP tier. ### How to qualify with \$YELLOW * Hold a **24-hour average** of \$YELLOW to qualify. * Only your **Trading Account (`Spot Account`)** balance counts. * For Google Sign-in users, \$YELLOW in Account Balance (`Yellow Wallet`) does **not** qualify. * \$YELLOW in external wallets does **not** count. For example, a 24-hour average of 10,000 \$YELLOW qualifies for VIP 1. See [VIP Tiers & Fee Discounts](/fees/vip-tiers) for all amounts. ## How \$YELLOW Supports the Platform A large portion of collected trading fees (85%) is allocated toward **\$YELLOW buybacks**, connecting platform activity to the token's value. See [Fee Split Explained](/fees/fee-split). ## Where to Get \$YELLOW \$YELLOW is currently available directly on Yellow\.pro — you can trade it, hold it in your Trading Account (`Spot Account`), or transfer it. Additional exchange listings may be added in the future. ## Related Articles * [VIP Tiers & Fee Discounts](/fees/vip-tiers) * [Fee Split Explained](/fees/fee-split) * [Trading Fees (Maker & Taker)](/fees/trading-fees) # How to Connect Your Wallet Source: https://docs.yellow.pro/getting-started/connect-your-wallet Step-by-step guide to connecting a supported wallet to Yellow.pro, plus WalletConnect tips and common connection troubleshooting. To start using Yellow\.pro, you first need to connect a supported wallet or sign in using Google. Yellow\.pro currently supports: * MetaMask * Rabby * Phantom * WalletConnect (560+ wallets) This guide explains how to connect an external wallet to the platform. Go to [yellow.pro](https://yellow.pro) and click the **Connect** button in the top-right corner of the screen. This opens the wallet connection window where you can choose your preferred login method. Select the wallet you want to use. Most users connect through MetaMask, Rabby, Phantom, or WalletConnect. If your wallet is not directly shown, use **WalletConnect** to search from 560+ supported wallets. After selecting your wallet: 1. your wallet application or browser extension opens 2. Yellow\.pro requests wallet connection approval 3. approve the connection inside your wallet Depending on the wallet you use: * browser extension wallets may open automatically * mobile wallets may require scanning a QR code * some wallets may open in a separate browser tab or redirect temporarily After approving the connection, your wallet asks you to sign a message. This signature is used only to authenticate your login session. Signing this message **does not move funds**, is **not a blockchain transaction**, and triggers **no trading action**. It only authenticates your session. You must complete both the **wallet connection approval** and the **signature request**. Cancelling either step means the wallet connection will not complete. Once connected successfully: * the Connect button is replaced with your balance display * your wallet address becomes visible in the account menu * Deposit and trading features become available You can now fund your account and start trading. ## Signing in with Google Google Sign-In option lets you create a Yellow wallet using your Gmail account. 1. Click **Connect** in the top-right corner. 2. Click **Login with Google**, below the wallet list. 3. Choose your Google account from the picker. 4. Approve the sign-in. Connect via Google Account Once signed in, the Connect button is replaced with your balance display, and Deposit and trading features become available. ## WalletConnect Users WalletConnect supports hundreds of wallets across desktop and mobile devices. A typical WalletConnect flow: 1. Select WalletConnect. 2. Choose your wallet. 3. Scan the QR code or open the wallet app. 4. Approve the connection. 5. Sign the authentication message. Connect via WalletConnect If your wallet browser extension is not installed, the platform may display **Not Detected** along with download options, mobile app links, or browser extension links. ## Common Connection Issues Sometimes the wallet signs successfully but the platform returns to the previous screen or does not log you in correctly. This can happen because: * browser pop-ups are blocked * redirect permissions are disabled * wallet authentication opened in another browser tab * browser cache caused session issues Try the following: 1. Allow pop-ups and redirects for Yellow\.pro. 2. Refresh the page after signing. 3. Try again using Incognito / Private mode. 4. Clear your browser cache if the issue continues. 5. Make sure the wallet app remains open during the process. This issue is more common with some WalletConnect-based wallets that use external authentication flows. If the QR code cannot be scanned: * reopen the wallet app * make sure the wallet supports WalletConnect connections If your wallet extension is installed but not detected: * refresh the browser * unlock the wallet extension * temporarily disable conflicting wallet extensions ## Disconnect or Log Out To disconnect from Yellow: 1. Go to the top-right corner of the screen. 2. Click on your balance. 3. In the pop-up window, click **Disconnect**. You don't need to sign any transaction to disconnect from the platform. ## Important Things to Know * Yellow\.pro supports only one active wallet connection at a time. * Wallet connection approval and message signing are both required. * Wallet signing does not give Yellow\.pro control over your funds. * If you cancel the signature request, the login session will not complete. * If your wallet is unsupported directly, use WalletConnect. ## Related Articles * [What is Yellow.pro?](/getting-started/what-is-yellow) * [External Wallet vs Google Account](/getting-started/wallet-vs-gmail) * [Users Journey on Yellow.pro](/getting-started/users-journey) * [How to Deposit](/deposits-and-withdrawals/how-to-deposit) # FAQ Source: https://docs.yellow.pro/getting-started/faq Quick answers to the most common questions about getting started on Yellow.pro. Yellow\.pro is a hybrid crypto trading platform that pairs the speed of a centralized exchange with the self-custody and transparency of DeFi, giving you fast, professional-grade order execution without handing over full control of your assets. You can trade **Spot** (buy and sell assets at live market prices) and **Perpetual Futures** (trade with leverage, go long or short, and manage positions with real-time P\&L and margin tracking). For more details, see [What is Yellow.pro?](/getting-started/what-is-yellow) External wallet users deposit and withdraw directly through their connected wallet without any additional balance layers. Google Sign-in users have their deposits first arrive in an Account Balance (`Yellow Wallet`) that must be transferred to their Trading Account (`Spot Account`) before trading. This means Google Sign-in users have a few extra transfer steps compared to external wallet users. For more details, see [External Wallet vs Google Account](/getting-started/wallet-vs-gmail) Yellow\.pro supports MetaMask, Rabby, Phantom, and WalletConnect (which supports 560+ additional wallets). If you sign in with Google, Yellow\.pro automatically creates a Yellow Wallet for you. For more details, see [How to Connect Your Wallet](/getting-started/connect-your-wallet) A Yellow Wallet is Abstraction Account Smart Contract owned by your email address and automatically created when you sign in using Google, serving as your Account Balance (`Yellow Wallet`) for deposits, withdrawals, and fund management. Your Yellow Wallet is also accessible and manageable on Yellow\.com, giving you flexible control over your funds across both platforms. For more details, see [Users Journey on Yellow.pro](/getting-started/users-journey) and [External Wallet vs Google Account](/getting-started/wallet-vs-gmail) Yellow\.pro currently supports the Ethereum blockchain only. This is a temporary limitation — more networks will be added over time as the platform grows. Always verify that the selected asset and network match before depositing or withdrawing — using the wrong network may result in permanent loss of assets. For more details, see [Users Journey on Yellow.pro](/getting-started/users-journey) # Glossary of Terms Source: https://docs.yellow.pro/getting-started/glossary Definitions of key terms used across Yellow.pro. Key terms used throughout Yellow\.pro and this documentation. For Google Sign-in users, the main balance where deposits first arrive and from which withdrawals are made. Funds must be transferred to the Trading Account before trading. Also accessible on Yellow\.com. External wallet users do not use Account Balance. See [Understanding Your Balances](/account-and-balance/understanding-your-balances). The mechanism that settles liquidations on Yellow\.pro: a liquidated position is matched against opposing traders, whose positions are partially closed. Priority is highest for the most profitable, highest-leverage positions on the opposite side. See [Cross-Margin Risk & ADL](/perpetual-trading/risk-and-liquidation/cross-margin-risk-and-adl). Funds you can use right now — for new orders or withdrawals. Equals total balance minus funds locked **In Orders** or committed as position margin. The mark price at which your account equity reaches zero. It sits just beyond your liquidation price, and is the price your position is force-settled at during liquidation. See [Liquidation & Mark Price](/perpetual-trading/risk-and-liquidation/liquidation-and-mark-price). In a pair like `ETH-USDT`, the **base** currency is the asset being bought or sold (ETH) and the **quote** currency is what you pay or receive (USDT). The margin mode used on Yellow\.pro perpetuals, where your entire available balance is shared collateral for all open positions. See [Margin & Leverage](/perpetual-trading/margin-and-leverage). A payment exchanged between long and short perpetual traders (usually every 8 hours) to keep the contract price near the market price. Not collected by Yellow\.pro. See [Funding Fees Explained](/fees/funding-fees-explained). A multiplier that lets you open a position larger than your margin (e.g. 10x). Amplifies both gains and losses. See [Margin & Leverage](/perpetual-trading/margin-and-leverage). An order to buy or sell at a specified price or better. Fills only at that price or better, and may not fill at all. See [Order Types](/spot-trading/order-types). The automatic closure of a position when your account can no longer meet maintenance margin (margin ratio reaches 100%). See [Liquidation & Mark Price](/perpetual-trading/risk-and-liquidation/liquidation-and-mark-price). The estimated mark price at which your account would be liquidated — where your equity falls to the maintenance margin level. In cross margin it moves with your PnL, positions, and balance. See [Liquidation & Mark Price](/perpetual-trading/risk-and-liquidation/liquidation-and-mark-price). The minimum margin required to keep a position open. If your effective margin falls below it, liquidation is triggered. On current markets the maintenance margin rate is a flat 0.5% of position notional. A **maker** order adds liquidity by resting in the order book; a **taker** order removes liquidity by filling immediately. Maker fees are lower. See [Trading Fees](/fees/trading-fees). A real-time indicator of how close your account is to liquidation. At 100%, liquidation is triggered. See [Margin & Leverage](/perpetual-trading/margin-and-leverage). An order that executes immediately at the best available price. Subject to slippage. See [Order Types](/spot-trading/order-types). A fair-value price derived from external reference data, used to calculate unrealized PnL and liquidation — instead of the last traded price — to reduce manipulation. See [Liquidation & Mark Price](/perpetual-trading/risk-and-liquidation/liquidation-and-mark-price). A blockchain transaction fee (currently Ethereum) for processing deposits and withdrawals on-chain. Set by the network, not Yellow\.pro. See [Withdrawal Network Fees Explained](/fees/withdrawal-network-fees). A separate balance used only for perpetual futures positions. Funds must be transferred here before opening perpetual positions, and cannot be withdrawn directly. See [Understanding Your Balances](/account-and-balance/understanding-your-balances). A derivative that tracks an asset's price with no expiry date. You never own the underlying asset. See [What is Perpetual Trading?](/perpetual-trading/what-is-perpetual-trading). Profit and Loss. **Unrealized** PnL is the current gain/loss on an open position (changes with the mark price); **Realized** PnL is locked in when you close. See [Understanding PnL](/perpetual-trading/pnl). Going **long** profits when the price rises; going **short** profits when it falls. See [Long, Short & Hedge Mode](/perpetual-trading/long-short-hedge-mode). The balance state for funds locked by active open orders (and, on Spot, by a withdrawal that's still processing). They return to Available when the order is filled or cancelled. On Perpetuals, funds can be In Orders too, but there is no withdrawal step. The direct exchange of one asset for another at the current market price — you own the asset you buy. See [What is Spot Trading?](/spot-trading/what-is-spot-trading). Conditional orders that activate at a trigger price, then submit a limit order (stop limit) or a market order (stop market). See [Order Types](/spot-trading/order-types). **Tick size** is the smallest allowed price increment; **step size** is the smallest allowed quantity increment for a market. Orders that don't align are rejected. The balance where Spot trading takes place. For external wallet users, deposits arrive here directly. See [Understanding Your Balances](/account-and-balance/understanding-your-balances). How long an order stays active before it's cancelled. **GTC** (Good 'Til Cancelled) rests until filled or cancelled — the default for limit orders; **IOC** (Immediate Or Cancel) fills what it can immediately and cancels the rest; **FOK** (Fill Or Kill) must fill completely and immediately or not at all. Market orders are always IOC. See [Order Types](/spot-trading/order-types#time-in-force-tif). A position mode that lets you hold a long and a short on the same pair simultaneously — currently the default on Yellow\.pro. One-Way Mode will be added later. See [Long, Short & Hedge Mode](/perpetual-trading/long-short-hedge-mode). Your fee level, set automatically by 30-day trading volume or your \$YELLOW balance. Higher tiers pay lower maker/taker fees. See [VIP Tiers & Fee Discounts](/fees/vip-tiers). Yellow\.pro's native token. Holding a 24-hour average in your Trading Account qualifies you for higher VIP tiers and lower fees. See [\$YELLOW Token & Fee Discounts](/fees/yellow-token-fee-discount). # Overview Source: https://docs.yellow.pro/getting-started/overview Start here to learn what Yellow.pro is and how to get set up. New to Yellow\.pro? These guides walk you through what the platform is, how it works, and how to get started. Hybrid crypto trading with self-custody. The connect, fund, transfer, trade, withdraw flow. How the two sign-in methods differ. Step-by-step connection guide. Definitions of key terms. Quick answers to common questions. # Users Journey on Yellow.pro Source: https://docs.yellow.pro/getting-started/users-journey The five-step Yellow.pro journey — connect, fund, transfer, trade, withdraw — and what to expect based on your account type. Yellow\.pro is designed to make trading simple while giving you full control over your assets. Whether you connect your own wallet or sign in using Google, the platform follows the same general journey. ## The Yellow\.pro Trading Flow 1. **Connect** your account 2. **Fund** your balance 3. **Transfer** funds (if needed) 4. **Trade** 5. **Withdraw** your assets This guide explains how each step works and what to expect based on your account type. Go to [yellow.pro](https://yellow.pro) and connect using one of these methods: * MetaMask * Rabby * Phantom * WalletConnect (supports 560+ wallets) * Google Sign-in **If you connect an external wallet,** Yellow\.pro uses that wallet directly for deposits and trading. **If you sign in with Google,** Yellow\.pro automatically creates a Yellow Wallet linked to your account, so you can use the platform without manually connecting a wallet. Once connected, your Yellow Wallet and balance become visible on the **Deposit** page. Funding works differently depending on your account type: * **External wallet users** — Deposits go directly from your connected wallet into your Trading Account (`Spot Account`). * **Google Sign-in users** — Deposits first arrive in your Account Balance (`Yellow Wallet`), then must be transferred to your Trading Account (`Spot Account`) before trading. For detailed instructions, see [How to Deposit](/deposits-and-withdrawals/how-to-deposit). Both account types may need to move funds between balances. * Transfers between Trading Account (`Spot Account`) and Perpetual Account are internal and normally instant. * Transfers involving Account Balance (`Yellow Wallet`) are processed on-chain and may take time. * Funds locked in open orders or active positions are not transferable. **Perpetual trading currently uses only USDT as collateral.** To open perpetual positions, transfer USDT into your Perpetual Account. For complete instructions, see [How to Transfer Funds Between Accounts](/account-and-balance/transfer-funds-between-accounts). Once funds are available in your Trading Account (`Spot Account`), you can begin trading. On the trading interface you can: * select a trading pair * choose between a Market or Limit order * enter the trade amount * place Buy or Sell orders Placed orders appear in **Open Orders** until they are completed or cancelled. Perpetual trading requires funds to be available inside the Perpetual Account. Withdrawal flows depend on your account type. For complete instructions, see [How to Withdraw](/deposits-and-withdrawals/how-to-withdraw). ## Important Reminders * Yellow\.pro currently supports the Ethereum blockchain only. This is a temporary limitation — more chains will be added over time. * Spot ↔ Perpetual transfers are internal and instant. * Account Balance (`Yellow Wallet`) ↔ Trading Account (`Spot Account`) transfers are processed on-chain. * Funds locked in open orders or active positions are not transferable. * Blockchain transactions cannot be reversed once completed. * Withdrawals and deposits are only possible to the connected wallet used to authorise to the platform. * Always verify the recipient wallet address before withdrawing from Account Balance (`Yellow Wallet`). **For Google Sign-in users especially:** if assets are withdrawn to the wrong wallet address, or to a blockchain that doesn't support smart wallet detection, the withdrawal may complete successfully on-chain but the funds may not be recoverable. Your Account Balance (`Yellow Wallet`) can also be managed on Yellow\.com for flexible fund management. ## Summary Yellow\.pro supports two main user flows: * **External wallet users** interact directly through their connected wallet and Trading Account (`Spot Account`). * **Google Sign-in users** use an additional Account Balance (`Yellow Wallet`) layer for deposits and withdrawals. Understanding how balances and transfers work helps avoid the most common deposit, transfer, and withdrawal issues on the platform. ## Related Articles * [What is Yellow.pro?](/getting-started/what-is-yellow) * [External Wallet vs Google Account](/getting-started/wallet-vs-gmail) * [How to Connect Your Wallet](/getting-started/connect-your-wallet) * [Understanding Your Balances](/account-and-balance/understanding-your-balances) # External Wallet vs Google Account Source: https://docs.yellow.pro/getting-started/wallet-vs-gmail How the two ways to access Yellow.pro — external wallet vs Google sign-in — differ in balance structure and deposit, transfer, and withdrawal flow. Yellow\.pro supports two ways to access the platform: 1. Connecting an external wallet 2. Signing in using Google Both methods let you trade on the platform, but the balance structure and transfer flow work differently. This guide explains the main differences and gives the complete deposit, transfer, and withdrawal flow for each account type. You can connect supported wallets such as MetaMask, Rabby, Phantom, or WalletConnect directly to Yellow\.pro. Deposits and withdrawals happen directly through the connected wallet. **External wallet users do NOT use Account Balance.** **Deposit flow** `External Wallet → Trading Account → Perpetual Account` Deposits go directly into the Trading Account. If you want to use funds for Perpetual trading, transfer them internally to the Perpetual Account. 1. Initiate a deposit from Yellow\.pro. 2. Approve the spending limit in case of ERC20 transaction (like USDT) 3. Approve the deposit transaction in your connected wallet. 4. Wait for on-chain execution. 5. Funds appear in your Trading Account. 6. Transfer to the Perpetual Account if needed for perpetual trading. **Withdrawal flow** `Perpetual Account → Trading Account → External Wallet` If funds are currently inside the Perpetual Account, they must first be transferred back to the Trading Account before withdrawal. 1. Go to the Withdrawal page. 2. Select the asset and amount. 3. Funds are sent directly to your connected wallet. 4. No recipient address needed — your wallet is already connected. **Transfer flow** `Trading Account ↔ Perpetual Account` Transfers between the Trading Account and Perpetual Account are internal platform transfers and normally reflect instantly. Spot Account To Perpetual Account Transfer If you sign in using Google, Yellow\.pro automatically creates a Yellow Wallet linked to your account. Deposits first arrive in your Account Balance (your Yellow Wallet) before they can be used for trading. **Deposit flow** `Account Balance (Yellow Wallet) → Trading Account → Perpetual Account` After depositing, funds must first be transferred from Account Balance to the Trading Account before trading is possible. 1. Initiate a deposit to your Account Balance using the shown on the interface address or by QR code. 2. Wait for on-chain execution. 3. Funds arrive in your Account Balance (Yellow Wallet). 4. Transfer funds from Account Balance to the Trading Account. 5. Wait for on-chain execution. 6. Once in the Trading Account, you can trade or transfer to the Perpetual Account. Account Balance to Trading Account Transfer **Withdrawal flow** `Perpetual Account → Trading Account → Account Balance (Yellow Wallet) → External Wallet` Withdrawals can only be processed through Account Balance. You must manually enter a recipient wallet address. 1. If funds are in the Perpetual Account, transfer them to the Trading Account first. 2. Transfer funds from the Trading Account to Account Balance. 3. Go to the Withdrawal page. 4. Enter the recipient wallet address (can be any external wallet). 5. Select the asset and amount. 6. Confirm the withdrawal. **Transfer flow** Perp Account -> Spot (Trading) Account To Account Balance Transfer `Account Balance ↔ Trading Account` and `Trading Account ↔ Perpetual Account` * Transfers between Account Balance and the Trading Account are processed on-chain and may take additional time depending on blockchain conditions. * Transfers between the Trading Account and Perpetual Account are internal and normally reflect instantly.
Your Account Balance (Yellow Wallet) is also accessible on Yellow\.com. Once funds reach your Account Balance, you have full control through either Yellow\.pro or Yellow\.com.
## Main Differences | Comparison | External Wallet Users | Google Sign-in Users | | ------------------------------------------- | -------------------------------------------- | ------------------------------------------------------ | | Wallet setup | User connects their own wallet | Yellow Wallet is created automatically | | Deposit destination | Trading Account | Account Balance (Yellow Wallet) | | Trading requirement | Funds can usually be traded immediately | Funds must first be transferred to the Trading Account | | Spot ↔ Perpetual transfers | Internal and normally instant | Internal and normally instant | | Withdrawal source | Trading Account (direct to connected wallet) | Account Balance (Yellow Wallet) | | Account Balance usage | Not used | Required for deposits and withdrawals | | Account Balance ↔ Trading Account transfers | Not applicable | Processed on-chain | | Recipient address on withdrawal | Connected wallet used automatically | User must enter recipient address manually | ## Important Things to Know * External wallet users interact directly through their connected wallet. They do not use Account Balance. * Google Sign-in users have an additional Account Balance layer (Yellow Wallet) for deposits and withdrawals. * Spot ↔ Perpetual transfers are internal and normally instant for both account types. * Account Balance ↔ Trading Account transfers are processed on-chain and may take time. * Funds locked in active orders or positions are not transferable. * Blockchain transactions cannot be reversed once completed. For Google Sign-in users, withdrawals can be sent to any external wallet address on a supported blockchain. There are two separate things to keep in mind: * **Wrong address or unsupported blockchain — possible loss of funds.** If assets are withdrawn to an incorrect address, or to a blockchain Yellow\.pro doesn't support, the funds may be permanently unrecoverable. Always double-check the destination address and network before confirming a withdrawal. * **Account-abstraction detection — a display limitation, not a loss.** Your Yellow Wallet is a smart (account-abstraction) wallet. External apps or wallets that don't support account abstraction may not automatically detect its balance, so your funds can appear "missing" in those apps even though they are safe. Contact the destination app support for resolution. ## Which Option Should You Choose? * **External wallet connection** is generally better for users already familiar with crypto wallets and direct wallet interaction. It's more straightforward since there's no Account Balance layer. * **Google Sign-in** is designed for users who want a simpler onboarding experience without manually connecting a wallet first. Your Yellow Wallet is created automatically and is also accessible on Yellow\.com. Both methods provide access to the same trading platform and features. Choose whichever feels most comfortable for your workflow. ## Related Articles * [What is Yellow.pro?](/getting-started/what-is-yellow) * [Users Journey on Yellow.pro](/getting-started/users-journey) * [Understanding Your Balances](/account-and-balance/understanding-your-balances) * [How to Transfer Funds Between Accounts](/account-and-balance/transfer-funds-between-accounts) * [How to Deposit](/deposits-and-withdrawals/how-to-deposit) * [How to Withdraw](/deposits-and-withdrawals/how-to-withdraw) # What is Yellow.pro? Source: https://docs.yellow.pro/getting-started/what-is-yellow Yellow.pro is a hybrid crypto trading platform that pairs centralized-exchange speed with the self-custody and transparency of DeFi. **Yellow\.pro** is a hybrid crypto trading platform that pairs the speed of a centralized exchange with the self-custody and transparency of DeFi. You get fast, professional-grade order execution without handing over full control of your assets. ## Flexible Access Access the platform with a **Web3 wallet** (MetaMask, Rabby, Phantom, WalletConnect) for full self-custody, or **sign in with Google** for an instant start through your Yellow Wallet. Either path gives you the same trading features and a clean, beginner-friendly interface. For how the two sign-in methods differ, see [External Wallet vs Google Account](/getting-started/wallet-vs-gmail). For the full connect → fund → trade → withdraw flow, see the [Users Journey](/getting-started/users-journey). ## What You Can Trade * **Spot Trading** — Buy and sell supported crypto assets at live market prices using market or limit orders. * **Perpetual Futures** — Trade with leverage on supported markets, go long or short, and manage positions with real-time P\&L, margin, and liquidation tracking. ## Why Traders Choose Yellow\.pro * **Fast Execution** — Low-latency matching built for active and high-frequency trading. * **You Stay in Control** — Non-custodial wallet support means your funds remain yours. * **Pro Tools, Simple UX** — Advanced order types and position management without unnecessary complexity. * **Growing Market Coverage** — New Spot and Perpetual markets are added over time. ## Related Articles * [Users Journey on Yellow.pro](/getting-started/users-journey) * [External Wallet vs Google Account](/getting-started/wallet-vs-gmail) * [Understanding Your Balances](/account-and-balance/understanding-your-balances) * [How to Transfer Funds Between Accounts](/account-and-balance/transfer-funds-between-accounts) * [How to Deposit](/deposits-and-withdrawals/how-to-deposit) # Welcome to Yellow! Source: https://docs.yellow.pro/index Yellow combines fast trading infrastructure with user-controlled custody — performance, clarity, and control in one place. Markets should be open, fast, and fair. Too often, traders are forced to choose between performance and control — speed at the cost of custody, or transparency at the cost of usability. Yellow takes a different approach: fast trading infrastructure with **user-controlled custody**. Trade spot and perpetual markets without giving up ownership of your assets. ### What Yellow Stands For * **Control stays with you** — your assets never disappear into a black box just to access the market. * **Trading is fast** — market participation shouldn't feel delayed, fragmented, or unnecessarily complex. * **Access is simple** — sign in with Google or connect your own wallet. * **Markets are easy to navigate** — funding, trading, transferring, and withdrawing feel like one clear system. ### Start Here New to Yellow? This is the best order to follow: Connect your wallet or sign in with Google. Deposit funds into your account. Move funds to your Trading Account. Place your first spot trade. Withdraw funds to your wallet. Want the full picture first? Read [What is Yellow.pro?](/getting-started/what-is-yellow) and the [Users Journey on Yellow.pro](/getting-started/users-journey). ### Need Help? If you're unsure about a step, check the [Getting Started FAQ](/getting-started/faq), the [Deposit & Withdrawal Troubleshooting](/deposits-and-withdrawals/troubleshooting) guide, or the relevant guide for that action. # Agentic Portfolio Source: https://docs.yellow.pro/mcp/agentic-portfolio Track your agent sub-account's holdings and performance separately from your main account. Your **Portfolio** page has a **Main / Agentic** toggle at the top, so you can look at the agent sub-account's holdings completely separately from your main account. Agentic portfolio view ## What the Agentic view shows Realized P\&L, Unrealized P\&L, Net funding, Leverage used, and Win rate — the same metrics as your main portfolio, scoped to just the agent account. Two donut charts: **Wallet allocation** (how the agent's balance splits between Spot and Perp) and **Asset breakdown** (by token, for example USDT on each side). For example *Claude Code · key 4fd1...d199*, showing its scopes as short tags (`read`, `trade`, `withdraw:spot — never`), with a reminder that withdrawals are disabled on agent accounts and funds must be transferred back to Main to move them out. The same breakdown tools you'd use on your main portfolio, filtered to the agent's activity. This is the best place to check on an AI agent's trading history at a glance, without it being mixed in with your own manual trades. # Manage Your API Keys Source: https://docs.yellow.pro/mcp/api-keys Review, freeze, and revoke the keys minted for each connected AI client. Every pairing mints a new API key for that client, scoped to exactly the permissions you chose. You can see and manage all of them from **API Key Management** in your account settings. API Key Management screen ## What each column shows | Column | What it tells you | | ------------------------ | ----------------------------------------------------------------------------------------------------------------------------- | | **API Key** | A truncated identifier. The full secret is never shown here. | | **AI / Client** | Which assistant the key belongs to, and its access level (for example *Read & trade*). | | **State** | An **Active** toggle. Switching it off instantly freezes that key. | | **Created** / **Expire** | When the key was minted and when it expires. Keys are valid for one year. | | **Last Used** | The most recent call the key made — useful for spotting a client that's gone quiet, or one that's calling more than expected. | ## Freezing a key Toggling **State** off is immediate and reversible, even if your AI is mid-session. It's the fastest way to cut off one AI client without touching any others connected to your account. ## Adding another key Click **Create** to mint an additional key manually, or go back through the [agent onboarding flow](/mcp/getting-started) to pair a brand-new client. A new key is minted for each AI you connect. Revoking one stops only that agent — the others keep working, and your account and balance are unaffected. # Choose your setup Source: https://docs.yellow.pro/mcp/choose-your-setup Three setups in increasing order of access and risk — market data only, full account access, then trading. Three environment variables and two flags is a lot to absorb at once. You don't need all of them. Pick the level you actually want and verify it works before adding the next one. ## Level 1 — Market data only No credentials at all. Proves the install and the client wiring with nothing at risk. ```bash theme={null} YELLOW_PRO_MODULES=market ``` You get prices, order books, klines, funding rates, and the supported networks and assets. Every tool in the [market module](/mcp/tools#market) works with no key. Start here even if you ultimately want trading. If market data works, the server is installed and your client is spawning it correctly — which eliminates most of the [troubleshooting](/mcp/troubleshooting) surface before credentials are involved. ## Level 2 — Full account access, still read-only Add the three credentials. You can now read balances, orders, positions, fills, fee tiers, and history. No order can be placed, because trading tools are not registered. ```bash theme={null} YELLOW_PRO_API_KEY=... YELLOW_PRO_API_SECRET=... YELLOW_PRO_APP_SESSION_ID=... YELLOW_PRO_MODULES=market,account ``` See [Getting your credentials](/mcp/credentials) for how to obtain these, and the [scope table](/mcp/credentials#scopes-and-tools) for which API-key permissions each group of tools needs. ## Level 3 — Trading Add the opt-in flag. Order placement, cancellation, position closing, leverage changes, and internal transfers become available. ```bash theme={null} YELLOW_PRO_ENABLE_TRADING=true ``` Read [Risk and safety](/mcp/risk-and-safety) before this step. Two tools — `cancel_all_orders` and `close_positions` — act on your **entire** account when called without a market, and they are single-word requests for an agent. ## Which module does what | Module | Credentials | Contains | | --------- | ----------------------------------------------- | ----------------------------------------------- | | `market` | Not required | Public market data | | `account` | Required (except `get_fee_schedule`) | Balances, orders, positions, history, fee tiers | | `trading` | Required, plus `YELLOW_PRO_ENABLE_TRADING=true` | Orders, position closing, leverage, transfers | Omitting `YELLOW_PRO_MODULES` loads all modules. Full details in [Configuration](/mcp/configuration). # Install Claude Code CLI Source: https://docs.yellow.pro/mcp/claude-code-cli Set up the Claude Code command-line tool on your machine before wiring in the Yellow.pro MCP server. Before installing an AI CLI, make sure you've completed Yellow\.pro's account setup first — connecting your wallet, creating a sub-account, and completing verification. See **[Agent Onboarding](/mcp/getting-started)** for the full walkthrough. The steps below assume your Yellow\.pro account is already set up and you're ready to pair an AI agent to it. **Claude Code** and **Claude Desktop** are two separate applications from Anthropic. Claude Desktop is the chat app (Chat/Cowork tabs); Claude Code is a command-line tool that runs in a terminal. The Yellow\.pro MCP server registers with Claude Code specifically — if you only have Claude Desktop installed, the steps on the [Installation](/mcp/installation) page will not find anywhere to register. If `claude --version` already works in your terminal, skip ahead to [Installation](/mcp/installation). Otherwise, follow the steps below first. Run the native installer for your platform: ```bash theme={null} theme={null} curl -fsSL https://claude.ai/install.sh | bash ``` ```powershell theme={null} theme={null} irm https://claude.ai/install.ps1 | iex ``` This downloads the `claude` binary directly — no separate Node.js or npm setup needed for this step. Open a **new** terminal window (a window that was already open won't see the updated `PATH`), then run: ```bash theme={null} theme={null} claude --version ``` A working install prints something like `2.1.263 (Claude Code)`. If you see `command not found: claude`, the installer likely finished without adding itself to your `PATH`. Fix it with: ```bash theme={null} theme={null} echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.zshrc && source ~/.zshrc ``` (Use `~/.bash_profile` instead of `~/.zshrc` if your shell is bash, not zsh.) Then open a fresh terminal window and re-run `claude --version`. If you see `claude native binary not installed`, the platform-specific binary failed to download. Re-run the installer above (not `npm install`) — this resolves it in almost all cases. Run: ```bash theme={null} theme={null} claude ``` This opens an interactive session and prompts you to sign in through your browser on first run. If you land on pay-per-use API billing instead of your subscription plan, run `/login` inside the session to switch. Claude Code requires a **Pro, Max, Team, Enterprise, or Console** account — the free Claude.ai plan does not include Claude Code access. Once logged in, exit back to your normal shell prompt (type `exit` or press `Ctrl+C`) before continuing to [Installation](/mcp/installation) — the Yellow\.pro setup commands are regular shell commands, not something you run inside an active Claude Code session. ## Troubleshooting **Terminal appears frozen after pasting a multi-line command.** This usually means a quote character was altered in transit (e.g. a straight `'` became a curly `'`), and the shell is silently waiting for you to close it — check whether your prompt reads `dquote>` or `quote>` instead of the normal prompt. Press `Ctrl+C` to cancel, then re-enter the commands one line at a time instead of pasting a multi-line block. Next: continue to [Installation](/mcp/installation) to install and register the Yellow\.pro MCP server with Claude Code. # CLI reference Source: https://docs.yellow.pro/mcp/cli The yellow-pro CLI covers the same surface as the MCP tools, but the command names differ — here is the mapping. Installing the package gives you a `yellow-pro` CLI alongside the MCP server. It covers the same surface, reads the same `YELLOW_PRO_*` environment variables, and respects the same trading opt-in. ```bash theme={null} yellow-pro --help ``` ## Command names differ from tool names The commands are shortened, so a tool name is not a valid command. Use this mapping when moving between an agent conversation and the terminal. | MCP tool | CLI command | | ------------------------- | ------------------------- | | `get_order_history` | `yellow-pro orders` | | `get_my_trades` | `yellow-pro trades` | | `get_transaction_history` | `yellow-pro transactions` | | `get_funding_rate` | `yellow-pro funding` | This table covers the commands whose names diverge most from their tool names. Run `yellow-pro --help` for the authoritative list on your installed version. ## Setup commands The CLI also registers the MCP server with your client: ```bash theme={null} yellow-pro setup claude-code yellow-pro setup codex yellow-pro setup openclaw yellow-pro setup hermes yellow-pro setup json ``` See [Installation](/mcp/installation) for what each one writes, including the `hermes` caveat. ## Trading from the CLI Trading commands follow the same gate as the MCP tools: they do nothing unless `YELLOW_PRO_ENABLE_TRADING` is set to `true`. The account-wide behaviour of cancel-all and close-all applies here too — see [Risk and safety](/mcp/risk-and-safety). # Install Codex CLI Source: https://docs.yellow.pro/mcp/codex-cli Set up OpenAI's Codex CLI on your machine before wiring in the Yellow.pro MCP server. Before installing an AI CLI, make sure you've completed Yellow\.pro's account setup first — connecting your wallet, creating a sub-account, and completing verification. See **[Agent Onboarding](/mcp/getting-started)** for the full walkthrough. The steps below assume your Yellow\.pro account is already set up and you're ready to pair an AI agent to it. If `codex --version` already works in your terminal, skip ahead to [Installation](/mcp/installation) and use `yellow-pro setup codex`. Otherwise, follow the steps below first. Install Codex CLI globally via npm: ```bash theme={null} theme={null} npm install -g @openai/codex ``` Alternative install methods: ```bash theme={null} theme={null} # macOS (Homebrew) brew install --cask codex ``` ```bash theme={null} theme={null} # Windows winget install OpenAI.Codex ``` Open a **new** terminal window (a window that was already open won't see an updated `PATH`), then run: ```bash theme={null} theme={null} codex --version ``` If you see `command not found: codex`, npm's global bin directory likely isn't on your `PATH`. Check where npm installs global packages with `npm config get prefix`, then add `/bin` to your `PATH` (e.g. in `~/.zshrc`) and open a fresh terminal window. Run: ```bash theme={null} theme={null} codex login ``` This opens a browser-based sign-in flow using your ChatGPT account. Check that it worked with: ```bash theme={null} theme={null} codex login status ``` For headless machines without a browser, use `codex login --device-auth` instead. To authenticate with an API key rather than a ChatGPT account, use `codex login --with-api-key` or set the `CODEX_API_KEY` environment variable. Next: continue to [Installation](/mcp/installation) and run `yellow-pro setup codex` to register the Yellow\.pro MCP server with Codex CLI. # Configuration Source: https://docs.yellow.pro/mcp/configuration Environment variables that control the Yellow.pro MCP server — credentials, environment selection, trading, module filtering, and rate limiting. The server is configured entirely through environment variables, set in your MCP client's config or your shell environment. ## Environment variables | Variable | Required | Default | Description | | --------------------------- | ------------- | -------------------------------- | ------------------------------------------------------------------------------ | | `YELLOW_PRO_BASE_URL` | No | selected by `YELLOW_PRO_SANDBOX` | Explicit REST base URL override | | `YELLOW_PRO_SANDBOX` | No | `false` | Case-insensitive `true` uses staging; any other value uses production | | `YELLOW_PRO_API_KEY` | Private tools | — | API key | | `YELLOW_PRO_API_SECRET` | Private tools | — | API secret (HMAC-SHA256) | | `YELLOW_PRO_APP_SESSION_ID` | Private tools | — | App session id, included in the request signature | | `YELLOW_PRO_ENABLE_TRADING` | No | off | Case-insensitive `true` enables trading tools; any other value leaves them off | | `YELLOW_PRO_MODULES` | No | all | Comma list of `market`, `account`, `trading` | | `YELLOW_PRO_RATE_LIMIT_MS` | No | `100` | Minimum gap between requests, in milliseconds | Both boolean flags are compared case-insensitively, so `true`, `True`, and `TRUE` all work. Anything else — including `1` and `yes` — counts as off. ## Environments By default the server talks to production at `https://trade.api.yellow.pro`. Setting `YELLOW_PRO_SANDBOX=true` switches to staging at `https://api.staging.yellow.pro.neodax.app`. An explicit `YELLOW_PRO_BASE_URL` takes precedence over sandbox mode. Credentials are environment-specific: keys created for staging do not work on production, and vice versa. Note that there is currently no documented way to obtain staging credentials — see [Getting your credentials](/mcp/credentials#environments). ## Credentials Market data tools work without any credentials. Everything else requires all three of `YELLOW_PRO_API_KEY`, `YELLOW_PRO_API_SECRET`, and `YELLOW_PRO_APP_SESSION_ID`. See [Getting your credentials](/mcp/credentials). One exception: `get_fee_schedule` lives in the `account` module but calls a public endpoint and needs no credentials. ## Enabling trading Trading tools are **not registered** unless `YELLOW_PRO_ENABLE_TRADING` is set to `true`. This is a deliberate safety default: with the flag off, an agent has no order-placing tool to call at all. Do not work around a disabled-trading state by calling the REST API directly. The opt-in flag exists so that order placement is a conscious choice. Read [Risk and safety](/mcp/risk-and-safety) first. ## Module filtering `YELLOW_PRO_MODULES` accepts exactly three tokens, comma-separated: ```bash theme={null} YELLOW_PRO_MODULES=market,account ``` | Token | Loads | | --------- | ------------------------------------------------------------- | | `market` | Public market-data tools | | `account` | Account state, history, fee tiers | | `trading` | Order placement, cancellation, position management, transfers | Omit the variable to load everything. Listing `trading` still has no effect unless `YELLOW_PRO_ENABLE_TRADING=true`. **Unrecognised module names are silently dropped** — no warning, no error. A plural typo such as `markets,account` yields account-only tools and looks like a broken install. If tools are missing, check this value character by character. ## Rate limiting `YELLOW_PRO_RATE_LIMIT_MS` sets the minimum gap between outbound requests, defaulting to 100 ms. Lowering this does not make the client more resilient. A `429` from the exchange is thrown immediately with no retry and no backoff, so an aggressive value converts throttling into hard failures. # Getting your credentials Source: https://docs.yellow.pro/mcp/credentials How to obtain the API key, secret, and app session id the MCP server needs for account and trading tools. Market data needs no credentials. Everything account-related needs all three of `YELLOW_PRO_API_KEY`, `YELLOW_PRO_API_SECRET`, and `YELLOW_PRO_APP_SESSION_ID`. The MCP server cannot create these for you. EIP-191 wallet signing and JWT authentication are deliberately not implemented in the server, so you obtain the key through the REST API (or the Yellow\.pro web UI) before configuring the MCP. ## Creating an API key The API key flow authenticates your wallet, exchanges the signature for a JWT, then uses that JWT to mint a key. `POST /auth/challenge` returns a challenge string to sign. See the [Authentication Service API](/api-and-programmatic-access/authentication-service-api). Sign the returned message with the wallet that owns the account. This is the EIP-191 step the MCP does not perform. `POST /auth/verify` returns a session and a JWT for the authenticated wallet. `POST /accounts/api-keys`, authenticated with that JWT, returns the key and secret. See [API Key Management](/api-and-programmatic-access/api-key-management). The secret is returned **once** and cannot be retrieved afterwards. Store it before closing the response. If you lose it, revoke the key and create a new one. You can also create and revoke keys from the web UI under **Settings → API Keys → Manage**. ## The app session id `YELLOW_PRO_APP_SESSION_ID` is required for every private request and is included in the request signature, so no account or trading tool works without it. A session identifier is returned by `POST /auth/verify` and surfaced by `GET /auth/me`. If you are unsure which value belongs in this variable, or whether yours has expired, contact [support](/community-and-resources/contact-support) rather than guessing — a wrong or stale value fails every private call. ## Scopes and tools API keys carry scopes. Granting only what you need avoids a class of `403` responses and limits the damage if a config file leaks. | Scope | Needed for | | --------------- | -------------------------------------------------------------------------- | | `read:spot` | Spot balances, spot accounts, open orders, order history, fills, fee rates | | `trade:spot` | Placing and cancelling spot orders | | `read:futures` | Perpetual positions, orders, position history, funding payments | | `trade:futures` | Perpetual orders, closing positions, changing leverage | | `withdraw:spot` | **Not needed.** The MCP exposes no withdrawal tool. | Because the server has no withdrawal tool at all, a key without `withdraw:spot` cannot move funds off the exchange no matter what an agent asks for. Leave that scope off. If a tool returns a permission error, check the key's scopes before anything else. See [Troubleshooting](/mcp/troubleshooting). ## Environments Credentials are environment-specific: keys created against production do not work against staging, and vice versa. There is currently no documented route to obtain a staging account or staging API keys. If you need to rehearse against staging, ask [support](/community-and-resources/contact-support) first — otherwise plan to test on production with small sizes and trading disabled. ## Where credentials are stored Credentials are sent only to the Yellow\.pro API, but the setup helpers write them to disk in cleartext: * `claude mcp add -s user` writes the key and secret to `~/.claude.json` * `yellow-pro setup openclaw` writes them to `~/.openclaw/openclaw.json` * The one-line installer places them in your shell history Treat those files as secrets. If one leaks, revoke the key immediately via `POST /accounts/api-keys` revocation or the web UI, then issue a new one. # Fund Your Agent Source: https://docs.yellow.pro/mcp/fund-your-agent Move USDT between your main account and the agent sub-account, instantly and with no network fee. A fresh agent sub-account starts at **0 USDT**. There's nothing for your AI to trade or report on until you move some balance into it. Read-only questions work fine against an empty account. You only need funds when you want the agent to trade. ## Open the transfer panel From your **Agent Overview** dashboard, click **Fund your agent** (or **Deposit** / **Transfer**). This opens the **Transfer** panel, where you move funds between your main account and the agent sub-account. Transfer panel, spot to AI spot account \_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_ Transfer panel, spot to AI perpetuals account | Field | What to choose | | ----------------- | -------------------------------------------------------------------------------------- | | **Transfer from** | Your main Spot or Perp account | | **Transfer to** | The AI Spot Account or AI Perpetuals Account, depending on where your AI needs balance | | **Token** | The asset (usually USDT) and an amount, or click **MAX** | **No fees, no delay.** Transfers between your main and agent accounts arrive instantly with no network fee — it's an internal move, not an on-chain transaction. ## After funding Once funded, your Agent Overview updates to show the new balance, and a green confirmation banner replaces the "account is empty" warning: > Everything is working. Your agent can read the account and place orders on it, up to the balance you gave it. Funded agent overview You can fund the Spot side, the Perpetuals side, or both — whatever your AI needs for the questions or trades you want it to handle. ## Moving funds back You can withdraw funds back to your main account from the same **Transfer** panel at any time. Only you can move funds out. The agent key itself can never initiate a withdrawal or transfer, regardless of the access level you granted it. If you ask your AI to withdraw, it will fail by design. # Agent Onboarding Source: https://docs.yellow.pro/mcp/getting-started Connect your wallet, create an agent sub-account, pair your AI client, and verify it works — the full walkthrough on yellow.pro. Give your AI its own Yellow\.pro trading account: a separate account under your login, with permissions you control. **What this covers** * Connect your wallet * Create a dedicated agent sub-account * Pair an AI client * Verify that it works * Fund the agent and try it out **Estimated setup time:** about 10 minutes the first time. An agent sub-account is a separate account under your main login, with its own balance. Your AI only ever touches funds you move into that sub-account, **never your main account**. An agent can **never withdraw**, regardless of which permissions you grant it. Withdrawals always require your signature on the main account. ## Step 1 — Connect your wallet Go to [yellow.pro](https://yellow.pro) and click **Connect** in the top-right corner. Connect button in the top-right of yellow.pro Pick a wallet — MetaMask, Phantom, Rabby, or WalletConnect — or continue with **Google**. Wallet selection dialog If you connect a wallet, approve two prompts from the wallet extension: 1. A connection request 2. A signature request (`"Please sign this message to authenticate..."`) **Signing is free.** The signature proves you own the wallet. It is not a transaction. Once connected, a welcome panel walks you through the quick path: deposit or convert to USDT, transfer spot to perpetual, and open your first position. You can follow it or skip it — click **Start trading** or **×** to dismiss. None of those steps are required before setting up your agent. Welcome to Yellow Pro panel ## Step 2 — Open the agent onboarding page Click **AI agent** in the top navigation bar. AI agent link in the top navigation This takes you to **Give your AI its own trading account**. Agent onboarding landing page The flow has four steps: **Agent sub-account**, **Connect**, **Verify**, and **Agent dashboard**. ## Step 3 — Create your agent sub-account The page explains what your AI will be able to do: | Capability | What it means | | ------------------------------------- | -------------------------------------------------------------------------- | | **Reads markets** | Prices, order books, funding rates | | **Reads its own account** | Balances, positions, orders | | **Trades only when you switch it on** | Off by default | | **Withdrawals stay with you** | An agent key can never withdraw or transfer out, regardless of permissions | Click **Create your agent account**. This creates the account only — no key and no funds yet. Create your agent account step Once created, Step 1 turns green and shows your new account: an **agent account ID** in the form `agentic:0x...` under your main account, with a **balance** starting at `0 USDT`. There is nothing to fund yet. You'll fund the account once your AI is connected. Agent sub-account created and ready ## Step 4 — Choose your AI and set its access Step 2, **Connect**, asks two questions. ### Which AI are you using? Seven clients currently work, each with a one-command setup. | AI client | Setup | | --------------- | ------------------------------------------ | | **Claude Code** | Recommended — one command, no file to edit | | **Generic AI** | Any MCP-compatible app | | **Codex CLI** | One command, TOML config | | **Gemini CLI** | One command, merges settings | | **Cursor** | One command, instant reload | | **Hermes** | One command, YAML config | | **OpenClaw** | One command, JSON5 config | Choosing an AI client and access level ### Should it be allowed to trade? Reads prices, positions and balances, and answers questions. Cannot trade. Scopes: `read:spot`, `read:perp` Places and cancels orders using the agent account's available margin. Adds: `trade:spot`, `trade:perp` Start with read-only. You can change the access level later from the agent dashboard without redoing this flow. ## Step 5 — Get your pairing code Yellow\.pro generates a one-time pairing code and the exact command that redeems it, pre-filled with your selected client and permission choices. Pairing code and copy command **This code is not your API key or secret.** It is a one-time claim that you redeem once. Redeeming it mints the actual key locally on your machine — Yellow\.pro never sees or stores that key. The code is single-use and expires in about 10 minutes, so don't generate it until you're ready for the next step. If it expires, click **Change and get a new code**. Click **Copy command**, then continue to the section for your client. ## Step 6 — Install your AI client, log in, and pair If your AI client isn't installed yet, set it up first: Recommended. Install, verify, and log in. OpenAI's CLI, if that's your client. **Claude Code and Claude Desktop are different applications.** Claude Desktop is the chat app with a window; Claude Code runs in your terminal. The pairing command registers with Claude Code specifically. ### Claude Code walkthrough ```bash theme={null} curl -fsSL https://claude.ai/install.sh | bash ``` Running the Claude Code installer Claude Code installed successfully Open a **new** terminal window and run: ```bash theme={null} claude --version ``` You should see a version number such as `2.1.267`. If you see `command not found`, add the install location to your `PATH`: ```bash theme={null} echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.zshrc && source ~/.zshrc ``` Then open a fresh terminal and try `claude --version` again. Run: ```bash theme={null} claude ``` Starting Claude Code The first time you run Claude Code in a new folder it asks whether you trust the workspace. Choose **Yes, I trust this folder**. Workspace trust prompt Next, choose **Claude account with subscription**. Selecting a login method Complete the browser sign-in that opens, then click **Authorize**. Authorizing Claude Code If you see `Claude Max or Pro is required to connect to Claude Code`, your Claude.ai account is on the free plan. Upgrade to **Pro, Max, Team, or Enterprise**, or sign in with an API key instead. You'll return to the terminal logged in, and can pick a colour theme. This only affects how Claude Code looks, so any option is fine. Choosing a colour theme If billing shows **pay-per-use** instead of your plan, type `/login` inside the session. Once confirmed, exit back to the normal prompt: ```bash theme={null} exit ``` Back in the same terminal — at the normal `%` prompt, **not inside Claude** — paste and run the command Yellow\.pro gave you in Step 5. This installs the Yellow\.pro MCP package and registers it with Claude Code in one go. Pasting the pairing command Pairing command output The confirmation shows the account type (`subaccount`), the granted scopes such as `read:spot` and `read:futures`, where the credential was saved locally, and whether trading was enabled. Whether trading is enabled is determined entirely by the permission level you selected in Step 4. **Restart required.** If the output includes `"restart_required": true`, exit the existing Claude session and run `claude` again so it picks up the new MCP server. Run `claude`, then inside the session: ``` /mcp ``` `yellow_pro` should show as **connected**. That's enough to continue — you'll ask it something in Step 9. ### Other supported clients The pairing command works the same way for all seven supported clients. Run the command Yellow\.pro generated for your selected client. Manual configuration paths for Gemini CLI, Cursor, Hermes, and OpenClaw are on the [Installation](/mcp/installation) page. ## Step 7 — Verify it's working Return to the Yellow\.pro tab. Step 2 should now show **Connected**, and Step 3, **Verify**, becomes active. Click **Verify connection**. This runs a set of read-only checks against your new key. Verify connection step **Safe verification.** Nothing is created and no order is placed. These checks are read-only and safe to re-run anytime. The checks confirm that the agent sub-account exists, that an active key is connected, and that your AI has actually made a successful call. ### If a check doesn't pass The most common causes are on the CLI side: If the client was already running when you paired it, look for `"restart_required": true` in the pairing output. Exit the client and start it again. Scroll back in your terminal and check for an error before the `"connected": true` confirmation. Make sure the pairing command was pasted into your normal shell prompt, not an active Claude or Codex session. Fix the issue, then click **Verify connection** again. ## Step 8 — Open your agent dashboard Once verification passes, Step 4 changes to **Live**. Click **Open dashboard**. Verification passed Open dashboard button You'll see your **Agent Overview**: the connected AI, key details, trading status, current portfolio, and transfer controls. Agent Overview dashboard From the dashboard you can revoke the key, change its trading permission, fund or withdraw from the agent sub-account, and connect another AI to the same account. If trading is off, the dashboard shows a **Trading OFF** badge and an **Enable trading** control. Turning it on applies to the agent account only. Dashboard with trading off ## Step 9 — See it in action A fresh agent sub-account starts with **0 USDT**. Click **Fund it** or **Deposit** on the dashboard to move balance from your main account before asking your AI to do anything that requires funds. See [Fund your agent](/mcp/fund-your-agent) for the full transfer flow. Read-only questions work fine with a zero balance. Then return to your AI client and try it out. Ask: *"What's the funding rate on BTC-PERP?"* Your AI reads live market data through the connected key. Funding rate answer Ask: *"What's my balance?"* Balance answer Or: *"What's my liquidation distance on my open positions?"* Liquidation distance answer Your AI reads the agent sub-account directly. If trading is enabled, ask the AI to place a small test order. Placing an order Then confirm the order appears in your dashboard. Pending order in the dashboard Ask your AI to withdraw funds to an external address. The request should fail, explaining that agent keys cannot withdraw and that withdrawals require your signature on the main account. Withdrawal blocked Once you've asked it something real, return to Yellow\.pro and click **Verify connection** again. Every check should now show as confirmed. ## Next steps Move USDT between your main and agent accounts. Review, freeze, or revoke keys. Track the agent's performance separately. Fixes for the most common issues. # Installation Source: https://docs.yellow.pro/mcp/installation Install the Yellow.pro MCP server, register it with your AI agent client, and verify it works. ## Prerequisites The installer clones over HTTPS and builds locally, so it needs: * **Node.js 18 or newer** * **`git`** and **`npm`** on your `PATH` * **Network access** to GitHub and the npm registry Relevant for locked-down machines and CI images: the install will fail without a `git` binary or outbound network. ## Install This package is **not published to the npm registry**. `npm install -g yellow-pro-mcp` will fail with a 404. Use one of the two paths below. ### Option A — one-line installer Installs from GitHub and registers with Claude Code in a single step: ```bash theme={null} curl -fsSL -H 'Accept: application/vnd.github.raw+json' \ 'https://api.github.com/repos/layer-3/yellow-pro-mcp/contents/install.sh?ref=main' | bash && \ YELLOW_PRO_API_KEY=... YELLOW_PRO_API_SECRET=... YELLOW_PRO_APP_SESSION_ID=... \ yellow-pro setup claude-code ``` The installer checks the Node version, builds in a temporary directory, installs a packed tarball globally, and cleans up afterwards. If the system npm prefix is not writable, it installs under `~/.local` instead and prints a `PATH` hint. The repository is public, so installation does not require GitHub credentials. If your environment does not permit `curl | bash`, inspect `install.sh` before running it. Note that credentials passed on the command line land in your shell history. ### Option B — local checkout ```bash theme={null} git clone https://github.com/layer-3/yellow-pro-mcp.git cd yellow-pro-mcp npm ci && npm run build npm install -g . ``` Either path gives you both the `yellow-pro-mcp` server and the `yellow-pro` CLI. ## Register with a client For Claude Code: ```bash theme={null} claude mcp add yellow_pro -s user \ -e YELLOW_PRO_API_KEY=... -e YELLOW_PRO_API_SECRET=... -e YELLOW_PRO_APP_SESSION_ID=... \ -- yellow-pro-mcp ``` ### Setup helpers | Command | What it does | | ------------------------------ | -------------------------------------------------------------------------------------------- | | `yellow-pro setup claude-code` | Registers via `claude mcp add` (user scope), passing your current `YELLOW_PRO_*` variables | | `yellow-pro setup codex` | Registers via `codex mcp add`, passing your variables; falls back to a `config.toml` snippet | | `yellow-pro setup openclaw` | Writes an `~/.openclaw/openclaw.json` mcpServers entry including your variables | | `yellow-pro setup hermes` | Registers via `hermes mcp add`; falls back to a `config.yaml` snippet | | `yellow-pro setup json` | Prints generic MCP JSON for any other client | **`hermes` is an exception.** The successful `hermes mcp add` path registers the server **without** passing your credentials, so account tools will fail with a missing-credentials error. Credentials only appear in the fallback YAML snippet, which is printed when the hermes binary is absent. Until this is fixed, add the environment block to your hermes config by hand after running setup. ## Manual configuration Add to `~/.codex/config.toml`: ```toml theme={null} [mcp_servers.yellow_pro] command = "yellow-pro-mcp" env = { YELLOW_PRO_API_KEY = "...", YELLOW_PRO_API_SECRET = "...", YELLOW_PRO_APP_SESSION_ID = "..." } ``` Add to the client's MCP config (e.g. `~/.openclaw/openclaw.json`): ```json theme={null} { "mcpServers": { "yellow_pro": { "command": "yellow-pro-mcp", "env": { "YELLOW_PRO_API_KEY": "..." } } } } ``` ## Verify it works Restart your client first — MCP servers connect at session start. **1. Confirm the server starts.** This handshake needs no credentials: ```bash theme={null} echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}}}' | yellow-pro-mcp ``` A healthy response looks like this — a `serverInfo` block and a clean exit: ```json theme={null} {"result":{"protocolVersion":"2024-11-05","capabilities":{"tools":{"listChanged":true}}, "serverInfo":{"name":"yellow_pro","version":"20260722"},"instructions":"..."},"jsonrpc":"2.0","id":1} ``` **2. Ask your agent for market data.** Something like *"get the BTCUSDT-PERP ticker from Yellow\.pro"*. A good answer returns a live price and 24h figures. This confirms the client is spawning the server and reaching the API — with no credentials involved. **3. Ask for a balance.** Only once step 2 works. *"What's my Yellow\.pro spot balance?"* exercises your credentials and signature. If step 2 passed and this fails, the problem is credentials, not installation — see [Troubleshooting](/mcp/troubleshooting). ## Update and uninstall **Update:** re-run the one-line installer, or `git pull` and `npm install -g .` in a local checkout. The server reports a date-based build version in `serverInfo.version`; compare it against the latest commit to tell whether you are current. **Uninstall:** ```bash theme={null} npm uninstall -g yellow-pro-mcp claude mcp remove yellow_pro ``` Remove the `mcpServers` entry by hand for clients configured manually, and revoke the API key if you no longer need it. ## Agent skill (non-MCP agents) For agents that don't speak MCP, the repository ships an agent skill at `skills/yellow-pro/SKILL.md` that teaches agents to use the `yellow-pro` CLI. Copy it into your agent's skills directory, for example `~/.claude/skills/yellow-pro/`. # Yellow.pro MCP Server Source: https://docs.yellow.pro/mcp/overview An MCP server and CLI that exposes the Yellow.pro exchange to AI agents — market data, account state, and opt-in trading. The Yellow\.pro MCP server exposes the exchange to AI agents such as Claude Code, Codex CLI, OpenClaw, Cursor, or any other MCP client. It provides market data, account state, and — when explicitly enabled — trading. It runs as a local stdio process and follows the same conventions as the official OKX, Bybit, and Alpaca exchange MCP servers. Source and latest releases: [github.com/layer-3/yellow-pro-mcp](https://github.com/layer-3/yellow-pro-mcp). The endpoint and request contracts follow the current [Yellow.pro API documentation](/api-and-programmatic-access/overview). ## Key characteristics Market data works without credentials. Trading tools are not registered unless you explicitly opt in. Runs as a local stdio process. Credentials are read from your environment or MCP client config and are sent only to the Yellow\.pro API. Load only the tool groups you need — market, account, or trading — via a single environment variable. Ships with a `yellow-pro` CLI covering the same surface, plus a skill file for non-MCP agents. ## What's included Installing the package gives you two commands: * `yellow-pro-mcp` — the MCP server that MCP clients spawn. * `yellow-pro` — a CLI covering the same surface (`yellow-pro --help`). Command names differ from tool names; see the [CLI reference](/mcp/cli). Built-in rate limiting and the opt-in cursor pagination protocol are handled for you. ## Before you start You need API credentials for anything account-related. The MCP **cannot create its own credentials** — EIP-191 wallet signing and JWT authentication are deliberately not implemented here, so you obtain keys through the API first. Market data only, full account access, or trading. See [Choose your setup](/mcp/choose-your-setup). Only needed beyond market data. See [Getting your credentials](/mcp/credentials). See [Installation](/mcp/installation). ## Compatible clients The server works with any MCP client. First-class `setup` helpers exist for Claude Code, Codex CLI, OpenClaw, and Hermes, plus a generic JSON output for every other client (Cursor, Claude Desktop, and so on). See [Installation](/mcp/installation). ## Scope Two things are intentionally **not** implemented: EIP-191/JWT authentication and WebSocket streams. The MCP uses API-key (HMAC-SHA256) authentication only. For those flows, use the [REST and WebSocket APIs](/api-and-programmatic-access/overview) directly. # Risk and safety Source: https://docs.yellow.pro/mcp/risk-and-safety What to understand before letting an agent trade on your Yellow.pro account — account-wide tools, credential storage, and safe rollout. Trading involves risk of loss. An AI agent placing orders adds a second kind of risk: a short, reasonable-sounding request can map to a much larger action than intended. ## Two tools act on your entire account **`cancel_all_orders` called without a `market` cancels every open order on that market type.** **`close_positions` called without a `market` closes every position leg.** Both are single-word requests for an agent — "cancel my orders", "close everything" — with no per-order confirmation step in the protocol. If you want a narrower action, make sure the market is specified. Treat these two as the reason to enable trading only when you are actively supervising the session. ## Roll out in stages Do not go from nothing to trading in one step. The [setup ladder](/mcp/choose-your-setup) exists for this: market data first, then read-only account access, then trading. Each level verifies before the next adds risk. ## Protect your credentials * **Grant minimum scopes.** In particular, leave `withdraw:spot` off — the MCP exposes no withdrawal tool, so the scope buys you nothing and removes the worst-case outcome. See the [scope table](/mcp/credentials#scopes-and-tools). * **Know where the secret lands.** Credentials are only ever sent to the Yellow\.pro API, but the setup helpers write them to disk in cleartext (`~/.claude.json`, `~/.openclaw/openclaw.json`) and the one-line installer puts them in your shell history. * **Revoke on exposure.** If a config file or shell history leaks, revoke the key immediately and issue a new one. See [API Key Management](/api-and-programmatic-access/api-key-management). * **Never commit credentials** to source control. ## Understand what the agent cannot do The server has no withdrawal tool and no position-mode switch. Funds cannot leave the exchange through the MCP, and `transfer` only moves value between your own spot and perpetual accounts. ## Review before you trust * Trading tools only exist when `YELLOW_PRO_ENABLE_TRADING=true`. Turn it off when you are not actively trading. * Review every order an agent proposes before letting it through, especially size and direction. * Remember that perpetual `place_order` does not set your real leverage — `set_leverage` does. See [Tools](/mcp/tools#perpetual-behaviour-worth-knowing). * All actions are initiated by you or your AI assistant; the maintainers are not responsible for losses from agent behaviour. # Tools Source: https://docs.yellow.pro/mcp/tools The full tool surface of the Yellow.pro MCP server — market data, account state, and opt-in trading — plus order types, timestamp units, and pagination. Tools are grouped into three modules. Market tools need no credentials; account and trading tools do. Trading is opt-in (see [Configuration](/mcp/configuration)). ## Market Available without credentials: `get_health`, `get_markets`, `get_ticker`, `get_orderbook`, `get_klines`, `get_funding_rate`, `get_funding_rate_history`, `get_networks`, `get_transfer_assets` `get_markets` does not fail if the perpetual side is unavailable. It returns `{"perp":{"unavailable":"..."}}` instead of an error, which an agent may report as "there are no perpetual markets". Check for that key before trusting an empty perp list. ## Account Require API credentials, with one exception noted below: `get_balance`, `get_open_orders`, `get_order_history`, `get_my_trades`, `get_positions`, `get_position_history`, `get_position_history_detail`, `get_spot_accounts`, `get_spot_account`, `get_perpetual_accounts`, `get_fee_schedule`, `get_fee_tier`, `get_market_fee_rate`, `get_transaction_history`, `get_funding_payments` **`get_fee_schedule` is public.** It calls a public endpoint and works with no credentials at all, despite sitting in this list. Because it lives in the `account` module, `YELLOW_PRO_MODULES=market` hides it — so a credential-free market-data agent needs `market,account` to reach the public fee schedule. Which API-key scope each group needs is in the [scope table](/mcp/credentials#scopes-and-tools). ## Trading (opt-in) Only registered when `YELLOW_PRO_ENABLE_TRADING=true`: `place_order`, `cancel_order`, `cancel_all_orders`, `close_positions`, `set_leverage`, `transfer` `cancel_all_orders` and `close_positions` act on your whole account when called without a `market`. See [Risk and safety](/mcp/risk-and-safety). ## Conventions Markets use native ids: spot as `ETHUSDT`, perpetual as `BTCUSDT-PERP`. Amounts and prices are decimal strings. All results are raw exchange JSON. ## Timestamp units differ per tool Three formats are in use. Passing the wrong one returns an **empty result set rather than an error**, so it reads as "no data" instead of a mistake. | Tool | Unit | | ---------------------------------------------------------------------------------------------- | ------------ | | `get_klines` | Milliseconds | | `get_transaction_history` | Unix seconds | | `get_my_trades`, `get_position_history`, `get_position_history_detail`, `get_funding_payments` | RFC3339 | ## Order types `place_order` supports these single-order types: Requires `price`. No `price`. Requires `price` and guarantees the order is maker-only. Requires both `trigger_price` and `price`. Requires `trigger_price`. `post_only` is accepted by the MCP but is **not currently listed** in the published [Spot Trading API](/api-and-programmatic-access/spot-trading-api) or [Perpetuals Trading API](/api-and-programmatic-access/perpetuals-trading-api) order types. Confirm with [support](/community-and-resources/contact-support) before relying on it — the exchange may reject the order. Perpetual trigger orders also accept an optional `trigger_type` of `stop_loss` or `take_profit`. Order queries return the classified conditional type, such as `stop_limit`, `stop_loss`, `take_limit`, or `take_profit`. `cancel_order` accepts either the request type (`trigger_*`) or these returned types and normalizes Spot cancellation. ### Time in force Not passed explicitly, `time_in_force` defaults to `gtc` for limit-style orders and `ioc` for market-style orders. ## Perpetual behaviour worth knowing Perpetual `place_order` always sends a `leverage` value, defaulting to `"1"`. The effective margin still follows your account and market settings, so passing leverage here does not change your real leverage — `set_leverage` is the actual control. There is no isolated-margin mode. Risk is aggregated across positions; see [Cross-Margin Risk & ADL](/perpetual-trading/risk-and-liquidation/cross-margin-risk-and-adl). ## Position modes (Perpetual) Perpetual markets have a per-market position mode, listed under `position_modes` in `get_perpetual_accounts`. A market holds separate long and short legs. Orders take `direction` `long` or `short`, defaulting from `side` and flipped by `reduce_only`. A market holds a single net position. The exchange requires `direction: "both"` — pass it explicitly, it is never inferred. Switching position modes is only available in the Yellow\.pro web UI, not through the MCP. ## Transfers `transfer` moves funds between your spot and perpetual accounts. Constraints from the [Account Transfers API](/api-and-programmatic-access/account-transfers-api): * Only stablecoins can move between spot and perpetuals. * Source and destination must differ. The MCP schema permits identical values, but the exchange rejects them. * Perpetuals-to-spot transfers are capped at 80% of `min(total - locked, available)`. ## Pagination Most list tools use the documented opt-in cursor protocol. Omit `cursor` for the first request; the MCP sends `use_cursor=true`. Pass the returned `next_cursor` to fetch the next page. `page_size` defaults to 50 and is capped at 100. Fill-level position history (`get_position_history_detail`) is cursor-native: its first request omits both `cursor` and `use_cursor`, and its `page_size` defaults to **200** with a maximum of **500**. The `yellow-pro` CLI covers this same surface under different command names — see the [CLI reference](/mcp/cli). # Troubleshooting Source: https://docs.yellow.pro/mcp/troubleshooting Common issues with the Yellow.pro MCP server — connection, authentication, permissions, and error behaviour. ## Client shows no tools / server fails to connect Use `yellow-pro setup claude-code` (or `claude mcp add` directly) rather than editing config files by hand. Claude Code reads MCP config from `~/.claude.json`, not `~/.claude/settings.json`. The client spawns the server without loading your shell profile, so `yellow-pro-mcp` must be on the client's `PATH`. Check with `which yellow-pro-mcp`. If the installer printed a PATH hint, add that directory to your profile and restart the client. Servers connect at session start, so restart the client after changing any MCP config. Confirm the server itself runs: ```bash theme={null} echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}}}' | yellow-pro-mcp ``` A healthy response contains a `serverInfo` block and exits cleanly. ## Some tools are missing Check `YELLOW_PRO_MODULES` character by character. Unrecognised names are silently dropped with no warning, so a plural typo like `markets,account` leaves you with account-only tools. The only accepted tokens are `market`, `account`, and `trading`. If trading tools specifically are absent, `YELLOW_PRO_ENABLE_TRADING` is not set to `true`. ## Authentication errors **`invalid_api_key`** Private tools need all three of `YELLOW_PRO_API_KEY`, `YELLOW_PRO_API_SECRET`, and `YELLOW_PRO_APP_SESSION_ID`, and they must match the environment you are hitting. Staging keys do not work on production, and vice versa. If you registered with `yellow-pro setup hermes`, the credentials were almost certainly not written — see the [hermes caveat](/mcp/installation#setup-helpers). **`invalid_timestamp`** Your machine clock is more than a few seconds off the exchange's. Sync it: ```bash theme={null} sudo sntp -sS time.apple.com ``` Use `chrony` or `ntp` to synchronize the system clock. **Permission / `403` errors on a tool that otherwise works** The API key is missing a scope. Check it against the [scope table](/mcp/credentials#scopes-and-tools) — reads and trades are separate scopes, and spot and futures are separate again. ## Trading commands fail with "trading is disabled" Set `YELLOW_PRO_ENABLE_TRADING=true` in the MCP client's env config. This is intentional. Do not work around this by calling the REST API directly. The flag exists so that order placement is a deliberate action. Read [Risk and safety](/mcp/risk-and-safety) first. ## Empty results instead of data Almost always a timestamp unit mismatch. The three formats in use — milliseconds, Unix seconds, and RFC3339 — vary per tool, and the wrong one returns an empty set rather than an error. See the [timestamp table](/mcp/tools#timestamp-units-differ-per-tool). ## Error behaviour worth knowing Rate-limit responses are thrown straight away — there is no retry and no backoff. Lowering `YELLOW_PRO_RATE_LIMIT_MS` therefore converts throttling into hard failures rather than slower requests. The default is 100 ms. There is no configurable timeout. The exchange sometimes returns an error body with a 200 status. The client converts these into thrown errors, which is the right behaviour but will look different from raw `curl` output if you are comparing the two. If the perpetual side is unavailable, `get_markets` returns `{"perp":{"unavailable":"..."}}` rather than erroring — so an agent may report that no perpetual markets exist. Check for that key before believing an empty list. ## Still stuck Contact [support](/community-and-resources/contact-support), or open an issue on [github.com/layer-3/yellow-pro-mcp](https://github.com/layer-3/yellow-pro-mcp). Include the `serverInfo.version` from the handshake above so the version you are running is unambiguous. # Contract Specifications Source: https://docs.yellow.pro/perpetual-trading/contract-specifications Perpetual contract specifications — tick size, step size, minimum order size and value, price band, max leverage, and maintenance margin — and why an order might not be accepted. Every perpetual order is checked against the contract's rules **before it's accepted**. An order that breaks any rule is **not created** — the platform blocks it at submission, so it never enters the order book or your Order History. **If you're unable to place an order, one of the rules below is the most likely reason.** This page lists the rules and the current values for each perpetual contract. ## Order Validation Rules | Rule | What it means | You can't place the order if… | | ---------------------- | ----------------------------------------------------------------------------------- | ---------------------------------------------------------------- | | **Tick size** | The smallest allowed price increment. Your price must be an exact multiple of it. | Price is not a multiple of the tick size. | | **Step size** | The smallest allowed amount increment. Your amount must be an exact multiple of it. | Amount is not a multiple of the step size. | | **Minimum order size** | The smallest amount (in the base asset) you can trade. | Amount is below the minimum. | | **Maximum order size** | The largest amount (in the base asset) per order. | Amount is above the maximum. | | **Minimum notional** | The smallest order *value* (price × amount, in USDT). | Order value is below the minimum notional. | | **Price band** | A limit price must stay within a range around the reference (mark) price. | Price is below **50%** or above **150%** of the reference price. | | **Maximum leverage** | The highest leverage allowed on the contract. | Selected leverage exceeds the maximum. | | **Available margin** | You must have enough free margin to open or increase the position. | Available margin is insufficient. | The **price band** is why a limit order placed far from the current price can be blocked even when its price is otherwise valid. It prevents fat-finger orders and trades at unrealistic prices. ## Contract Specifications | Contract | Min order | Max order | Step size | Tick size | Price band | Min notional | Max leverage | Maintenance margin | | ---------------- | --------- | ------------- | --------- | --------- | ----------------------- | ------------ | ------------ | ------------------ | | **BTCUSDT-PERP** | 0.001 BTC | 1,000,000 BTC | 0.001 | 0.1 | 50% – 150% of reference | 1 USDT | 100× | 0.5% | | **ETHUSDT-PERP** | 0.001 ETH | 1,000,000 ETH | 0.001 | 0.01 | 50% – 150% of reference | 1 USDT | 100× | 0.5% | The **maintenance margin rate (MMR)** is the fraction of position notional you must keep to avoid liquidation. See [Margin & Leverage](/perpetual-trading/margin-and-leverage) and [Liquidation & Mark Price](/perpetual-trading/risk-and-liquidation/liquidation-and-mark-price) for how leverage and maintenance margin affect your positions. ## Market-order slippage tolerance A market order opens immediately at the best available price, so the fill price can differ from the mark price shown at submission. To stay funded if it fills at a worse price, a market order reserves about **5% extra initial margin** on top of the normal requirement. ## Worked Examples You place a limit order on **BTCUSDT-PERP** at **60,000.05**. The tick size is **0.1**, so the price must end at a multiple of 0.1 (e.g. `60,000.0` or `60,000.1`). You won't be able to place it — round your price to the tick size and try again. With BTC trading around **60,000**, you place a limit buy at **20,000** — below **50%** of the reference price (30,000). The order falls outside the price band, so it's blocked. Place the order within the allowed range around the current price. You try to open a **0.0005 BTC** position on BTCUSDT-PERP. The minimum order size is **0.001** and the step size is **0.001**, so `0.0005` is both too small and not a valid increment. Use `0.001`, `0.002`, and so on. ## Related Articles * [Margin & Leverage](/perpetual-trading/margin-and-leverage) * [Liquidation & Mark Price](/perpetual-trading/risk-and-liquidation/liquidation-and-mark-price) * [FAQ](/perpetual-trading/faq) # FAQ Source: https://docs.yellow.pro/perpetual-trading/faq Quick answers about perpetual trading on Yellow.pro — basics, position management, and risk & liquidation. ## Perpetual Basics A perpetual contract is a derivative — you trade a contract that tracks an asset's price, not the asset itself, so you never own the cryptocurrency. Unlike spot, perpetuals offer leverage, can lose more than your initial margin, and have **no expiry** (they stay open until you close them or are liquidated). See [What is Perpetual Trading?](/perpetual-trading/what-is-perpetual-trading). Going **long** means you expect the price to rise (you profit if it rises, lose if it falls). Going **short** means you expect it to fall (you profit if it falls, lose if it rises). This lets you profit in both bull and bear markets. See [Long, Short & Hedge Mode](/perpetual-trading/long-short-hedge-mode). Cross margin uses your **entire account balance** as shared collateral for all open positions. A profitable position can buffer a losing one, but a single bad position can draw from your whole balance. Yellow\.pro uses cross margin as the primary mode. See [Margin & Leverage](/perpetual-trading/margin-and-leverage). Yes — Yellow\.pro currently uses **Two-Way (Hedge) Mode by default**, so you can hold independent long and short positions on the same pair simultaneously. **One-Way Mode** (where opening the opposite side reduces or closes your existing position) will be supported in a future update. See [Long, Short & Hedge Mode](/perpetual-trading/long-short-hedge-mode). Leverage lets you control a position larger than your balance (e.g. 100 USDT at 10x = a 1,000 USDT position). Profit and loss are calculated on the full position size, so higher leverage means higher reward potential **and** higher liquidation risk. See [Margin & Leverage](/perpetual-trading/margin-and-leverage). Unrealized PnL is the current profit/loss on an open position; it changes as the mark price moves. Long: `(Mark − Entry) × Quantity`. Short: `(Entry − Mark) × Quantity`. It's "unrealized" because it's not locked in until you close. See [Understanding PnL](/perpetual-trading/pnl). The profit or loss locked in when you fully or partially close a position. Once realized it's added to or subtracted from your balance and isn't affected by future price movements. See [Understanding PnL](/perpetual-trading/pnl). Open positions and orders reserve a portion of your balance as margin. **Total Balance** is all funds; **Available Balance** is what isn't committed to positions or orders. In cross margin this is calculated across all positions together. The order form's **TIF** dropdown supports **GTC** (Good 'Til Cancelled — the default for limit orders), **IOC** (Immediate Or Cancel), and **FOK** (Fill Or Kill). Market orders are always IOC. See [Order Types](/spot-trading/order-types#time-in-force-tif). ## Position Management Yes. In cross margin you add to your buffer by adding funds to your account — this benefits all positions at once. You can withdraw only your available balance, not margin committed to open positions. See [Adjusting Margin & Leverage](/perpetual-trading/position-management/adjusting-margin-and-leverage). If supported, yes — but it changes your required margin and liquidation price. **Increasing leverage moves your liquidation price closer to the current price.** Always check the new liquidation price afterwards. See [Adjusting Margin & Leverage](/perpetual-trading/position-management/adjusting-margin-and-leverage). In the Positions panel, click Close on the position, enter a quantity **less than** your full size, choose market or limit, and confirm. The rest stays open at the original entry price. See [Closing a Position](/perpetual-trading/position-management/closing-a-position). In Two-Way Mode, long and short on the same pair are independent and margin is calculated separately for each. In cross margin both draw from the same balance, so the combined requirement is the sum of both positions' maintenance margins. In cross margin your liquidation price is dynamic — based on total balance, total unrealized PnL, and total maintenance margin. Any change (adding margin, opening a position, price moves) recalculates it for all positions. This is expected. ## Risk & Liquidation Liquidation triggers when your account margin ratio reaches 100% (equity at the maintenance-margin level). Your positions are then taken over and settled against opposing traders through auto-deleveraging (ADL), at your liquidation price (or the bankruptcy price as a fallback). Any balance left after settlement stays in your account, and you never owe more than you deposited. See [Liquidation & Mark Price](/perpetual-trading/risk-and-liquidation/liquidation-and-mark-price). The mark price is a fair-value price from external reference data, used for liquidation and PnL instead of the last traded price. The chart (last traded price) can differ from the mark price — if the mark price reaches your liquidation level, you're liquidated even if the chart hasn't moved as far. See [Liquidation & Mark Price](/perpetual-trading/risk-and-liquidation/liquidation-and-mark-price). All positions share one collateral pool, so liquidation is assessed on your whole account. A large loss on one position can raise the account margin ratio and liquidate everything — including profitable positions. See [Cross-Margin Risk & ADL](/perpetual-trading/risk-and-liquidation/cross-margin-risk-and-adl). Auto-Deleveraging (ADL) is how liquidations are settled: a liquidated position is matched against opposing traders, whose positions are partially closed. Your ADL priority rises with high unrealized profit and high leverage — so take profit or reduce leverage to lower it. Being ADL'd is not a penalty: you realize your PnL up to the settlement price. See [Cross-Margin Risk & ADL](/perpetual-trading/risk-and-liquidation/cross-margin-risk-and-adl). Act immediately: log in, check your margin ratio, add funds or reduce exposure. Alerts go to the email linked to your account, and your email is **never linked automatically** — whatever your login method, link it manually under `yellow.pro/settings` → Linked Socials, or you won't receive warnings. See [Margin Warnings & Risk Management](/perpetual-trading/risk-and-liquidation/margin-warnings-and-risk-management). Use stop-losses, add margin, reduce position size or leverage, keep free margin, and monitor your margin ratio. See [Margin Warnings & Risk Management](/perpetual-trading/risk-and-liquidation/margin-warnings-and-risk-management). # Long, Short & Hedge Mode Source: https://docs.yellow.pro/perpetual-trading/long-short-hedge-mode Going long or short on Yellow.pro perpetuals, and using two-way (hedge) mode to hold both directions on the same pair at once. In perpetual trading you can profit in both rising and falling markets by choosing your **position direction** — and, with hedge mode, hold both directions on the same pair at once. ## Going Long When you **go long**, you're betting the price will **increase**. You profit if it rises and lose if it falls. > **Example:** open a long on ETH-USDT at 2,000 with 10x leverage; ETH rises to 2,200 → your position gains 200 USDT per ETH, amplified by leverage relative to the margin used. Simplified: `PnL = (Exit Price − Entry Price) × Position Size`. If the price falls far enough, the position is liquidated. ## Going Short When you **go short**, you're betting the price will **decrease**. You profit if it falls and lose if it rises. > **Example:** open a short on ETH-USDT at 2,000 with 10x leverage; ETH drops to 1,800 → your position gains 200 USDT per ETH. Simplified: `PnL = (Entry Price − Exit Price) × Position Size`. Losses on a short are theoretically unlimited if the price keeps rising, so risk management is especially important. | | Long | Short | | ----------- | -------------------- | ------------------------------------- | | Market view | Bullish (price up) | Bearish (price down) | | Profit when | Price rises | Price falls | | Loss when | Price falls | Price rises | | Max loss | Position size (100%) | Unlimited (price can rise infinitely) | ## One-Way vs Two-Way (Hedge) Mode Yellow\.pro supports **both** position modes, and you choose which to use **per market, per account** — so you can run One-Way on BTC-PERP and Hedge on ETH-PERP at the same time. * **One-Way Mode** — one net position per market. Long and short orders net against each other automatically, so opening the opposite side reduces or closes your existing position. Simpler PnL and simpler closes — ideal for traders who think in terms of net exposure. * **Two-Way Mode (Hedge Mode)** — hold a **long and a short on the same pair simultaneously**, independently of each other. Useful for straddle strategies or locking in gains on one leg while keeping the other open. A long and a short position held on the same market at the same time in Two-Way (Hedge) Mode | | One-Way Mode | Two-Way Mode | | ------------------------- | -------------------------------- | ---------------------------------- | | Long + short on same pair | Not allowed | Allowed | | Opening opposite side | Reduces/closes existing position | Creates a new independent position | | Complexity | Lower | Higher | | Best for | Directional traders | Hedging strategies | ### When to use hedge mode * **Hedging a long** — open a short to offset a temporary decline without closing your long. * **Strategy separation** — run a longer-term long and a short-term short, tracked separately. * **Reducing directional bias** — test both sides and close whichever proves wrong. Each direction is an independent position with its own entry price, size, and PnL. In cross margin, both draw from the same balance. Hedge mode does **not** eliminate risk — both positions can lose in a choppy market. ## Related Articles * [Margin & Leverage](/perpetual-trading/margin-and-leverage) * [Understanding PnL](/perpetual-trading/pnl) * [Risk & Liquidation](/perpetual-trading/risk-and-liquidation) # Margin & Leverage Source: https://docs.yellow.pro/perpetual-trading/margin-and-leverage How cross margin, leverage, initial and maintenance margin, and the margin ratio work for perpetual trading on Yellow.pro. Yellow\.pro uses **cross margin** for perpetual trading, combined with adjustable **leverage**. Understanding how they interact is key to managing risk. ## Cross Margin In **cross margin** mode your **entire available Perpetual account balance** acts as collateral for all open positions — they share one margin pool. This is the margin mode used on Yellow\.pro. * A profitable position can provide buffer for a losing one. * A single heavily losing position can draw from your whole balance. * Liquidation triggers when your **total** account margin ratio hits the maintenance threshold — not per individual position. \> **Example:** a long BTC position up +200 USDT and a short BTC position down −150 USDT net to +50 USDT. Cross margin considers the whole account, so the losing leg isn't liquidated on its own. | | Cross Margin | Isolated Margin | | --------------------- | ------------------------------ | ----------------------------------- | | Collateral | Full perpetual account balance | Fixed amount per position | | Liquidation scope | All positions share risk | Each position risks only its margin | | Max loss per position | Up to full account balance | Only the isolated margin | Yellow\.pro currently uses **cross margin** as the primary mode. Isolated margin may be introduced in future updates. ## Leverage **Leverage** is a multiplier that lets you open a position larger than your account balance: `Position Size = Margin × Leverage`. With 100 USDT and 10x leverage you control a 1,000 USDT position. Leverage amplifies both gains **and** losses against the full position size: | Leverage | Margin | Position Size | 5% gain | 5% loss | | -------- | -------- | ------------- | --------- | --------- | | 1x | 100 USDT | 100 USDT | +5 USDT | −5 USDT | | 10x | 100 USDT | 1,000 USDT | +50 USDT | −50 USDT | | 20x | 100 USDT | 2,000 USDT | +100 USDT | −100 USDT | Higher leverage moves your **liquidation price closer** to entry and leaves less buffer for fluctuations. Beginners should start low (1x–5x). ## Initial vs Maintenance Margin * **Initial Margin** — the minimum required to open a position: `Initial Margin = Position Size / Leverage`. * **Maintenance Margin** — the minimum required to **keep** a position open. If your effective margin falls below it, liquidation is triggered. It's a fixed percentage of position size, lower than the initial margin. ## Margin Ratio The **Margin Ratio** is a real-time indicator of how close you are to liquidation: | Margin Ratio | Meaning | | ---------------- | --------------------------------------------- | | Low (e.g. \<50%) | Well-funded, low risk | | High (e.g. >80%) | Risk increasing — consider reducing positions | | 100% | Liquidation triggered | ## Keeping Your Margin Ratio Safe The main levers are adding margin, reducing position size, lowering leverage, and using stop-loss orders. You'll also receive an email warning as your margin ratio approaches critical levels. For the full approach and how to enable alerts, see [Margin Warnings & Risk Management](/perpetual-trading/risk-and-liquidation/margin-warnings-and-risk-management); for how liquidation is triggered and priced, see [Liquidation & Mark Price](/perpetual-trading/risk-and-liquidation/liquidation-and-mark-price). ## Related Articles * [Long, Short & Hedge Mode](/perpetual-trading/long-short-hedge-mode) * [Risk & Liquidation](/perpetual-trading/risk-and-liquidation) * [Cross-Margin Risk & ADL](/perpetual-trading/risk-and-liquidation/cross-margin-risk-and-adl) # Overview Source: https://docs.yellow.pro/perpetual-trading/overview Trade perpetual futures with leverage on Yellow.pro. Learn how perpetual trading works, how to manage risk, and how to manage your positions. Leveraged contracts with no expiry. Direction and two-way mode. Cross margin, leverage, and margin ratio. Unrealized and realized PnL. Liquidation, mark price, ADL, and risk. Adjust margin, leverage, and close positions. Tick size, step size, price band, leverage, and why orders get rejected. Quick answers about perpetual trading. # Understanding PnL Source: https://docs.yellow.pro/perpetual-trading/pnl Unrealized vs realized PnL in perpetual trading — how each is calculated and how the mark price drives your unrealized PnL. **PnL** (Profit and Loss) measures how much you've gained or lost on a position. In perpetual trading there are two types: **Unrealized** and **Realized**. Unrealized and realized PnL shown on a position ## Unrealized PnL (uPnL) The current gain or loss on an **open** position. It updates in real time as the market moves and affects your account equity and liquidation risk — but isn't locked in until you close. * **Long:** `uPnL = (Current Mark Price − Entry Price) × Position Quantity` * **Short:** `uPnL = (Entry Price − Current Mark Price) × Position Quantity` > **Long example:** entry 2,000, mark 2,200, size 1 ETH → `(2,200 − 2,000) × 1 = +200 USDT`. **Short example:** entry 2,000, mark 1,800, size 1 ETH → `(2,000 − 1,800) × 1 = +200 USDT`. Yellow\.pro uses the **Mark Price** (not the last traded price) to calculate uPnL, which protects against price manipulation. See [Liquidation & Mark Price](/perpetual-trading/risk-and-liquidation/liquidation-and-mark-price). ## Realized PnL The profit or loss **locked in** when you close a position fully or partially. Once realized, it becomes part of your balance and no longer changes with the market. Triggered by closing a position or by liquidation. Trading fees are deducted from realized PnL, so your net may be slightly less than the gross calculation. ## PnL and Your Account Balance | Component | What it includes | | ----------------- | ------------------------------------- | | Total Balance | All funds + unrealized PnL | | Available Balance | Funds not committed to open positions | | Unrealized PnL | Changes constantly with the market | | Realized PnL | Fixed after a position is closed | If your unrealized PnL is negative, your Total Balance appears lower than your deposited funds — this is normal; the loss is only confirmed when you close. Open positions tie up allocated margin and any open orders lock funds, reducing available balance. Unrealized PnL does adjust available balance (profit raises it, loss lowers it), but the collateral keeping positions open isn't free to use until you reduce or close them. ## Related Articles * [Long, Short & Hedge Mode](/perpetual-trading/long-short-hedge-mode) * [Liquidation & Mark Price](/perpetual-trading/risk-and-liquidation/liquidation-and-mark-price) * [Position Management](/perpetual-trading/position-management) # Adjusting Margin & Leverage Source: https://docs.yellow.pro/perpetual-trading/position-management/adjusting-margin-and-leverage How to add or remove margin and change leverage on an open perpetual position, and how each affects your liquidation price. In cross margin mode your entire available balance is shared collateral for all positions, so adjusting margin and leverage works a little differently than in isolated-margin systems. ## Adding Margin (Increasing Your Buffer) There's no separate "add margin to position X" control in cross margin — you increase the buffer for **all** positions by adding funds: 1. **Deposit additional funds** into your Yellow\.pro account. 2. Once credited and transferred to your **Perpetual** account, your available balance increases. 3. Your liquidation price moves **further** from the current market price for all open positions. ## Removing Margin You can withdraw only your **Available Balance** — not funds committed to open positions. To free up more, **close or reduce** positions first. Adding funds buys you more time if the market moves against you. You'll receive a [margin warning](/perpetual-trading/risk-and-liquidation/margin-warnings-and-risk-management) as your account approaches liquidation. ## Changing Leverage You can change a market's leverage **only when you have no open orders** on that market. Cancel any open orders on the market first, then adjust the leverage. 1. Open your **open positions** panel. 2. Find the leverage setting for the market. 3. Adjust the multiplier with the selector. 4. Confirm the change. The leverage selector on an open position | Action | Liquidation price | Margin required | | ----------------- | ------------------------- | --------------- | | Increase leverage | Moves closer to market | Decreases | | Decrease leverage | Moves further from market | Increases | **Increasing leverage on an open position moves your liquidation price closer to the current price** — a smaller adverse move can liquidate you. Always check your new liquidation price after changing leverage, and don't increase leverage on a position already under margin pressure. If mid-position adjustment isn't available, close and reopen the position with the new leverage. ## Related Articles * [Closing a Position](/perpetual-trading/position-management/closing-a-position) * [Margin & Leverage](/perpetual-trading/margin-and-leverage) * [Liquidation & Mark Price](/perpetual-trading/risk-and-liquidation/liquidation-and-mark-price) # Closing a Position Source: https://docs.yellow.pro/perpetual-trading/position-management/closing-a-position How to close a perpetual position fully or partially on Yellow.pro, and what happens to your margin and realized PnL. Closing a position locks in your **Realized PnL** and releases its margin back to your Available Balance. There are two ways to close: a one-click market close, or a controlled close through the order form. ## Quick Close (the ✕ button) Clicking the **✕** next to a position in the **Positions** panel places an immediate **market order** to close the **entire** position — there are no order-type or amount options. It fills against the best available prices straight away; if there isn't enough liquidity to match it, it fills **partially** and the remainder **expires**. It's the fastest way out, with the least control — use it when you just need to exit. Closing a position with the ✕ button in the Positions panel ## Controlled Close (order form → Close tab) For full control — including partial closes and specific exit prices — close through the order form instead of the ✕ button: 1. Switch the order form to the **Close** tab. 2. Choose the order type: **Market**, **Limit**, or **Stop**. 3. Enter the **amount** to close — your full size, or less for a partial close. 4. Confirm. A **Limit** close lets you exit at a specific price or better (e.g. a take-profit level); a **Stop** close triggers at a price you set. A **partial** close leaves the rest of the position open at the original entry price, with margin adjusting proportionally. Resting limit or stop closes wait in **Open Orders** until they fill or you cancel them. Closing through the order form's Close tab > **Example:** you hold 2 ETH long and close 1 ETH → your position becomes 1 ETH long, and half the margin is released. Take Profit / Stop Loss orders must currently be set manually — they are not automatically linked to a position. ## Reduce only Orders A **reduce-only** order is a flag you can add to an order to guarantee it can only close an existing position — it can never open a new one or increase the size of the one you already hold. It's a safety mechanism for exiting positions without any risk of accidentally flipping direction or adding exposure. * **Position-aware validation** — before a reduce-only order is accepted, the system checks that you have an open position **in the correct direction** with enough available size to reduce. * **Clear error guidance** — if you have no open position, or if the order side would increase rather than reduce it, you get a plain-language message explaining exactly what's wrong. * **One-Way aware** — in [One-Way Mode](/perpetual-trading/long-short-hedge-mode), a reduce-only order automatically resolves to the correct leg based on your net position direction. **When to use:** you're placing a take-profit or stop order and want to be certain it can only ever shrink your position — never open a fresh one if your position has already closed. Reduce-only is especially useful with resting limit or stop orders: if your position is already closed by the time the order triggers, a reduce-only order simply does nothing instead of opening an unwanted new position. ## After Closing * **Realized PnL** is credited or debited from your balance (trading fees are deducted). * The position leaves the Positions panel and the closed trade appears in **Trade History**. * In cross margin, closing one position can affect the others — always check your remaining balance. **Tip:** use the **✕ quick close** (market) to exit fast — e.g. to avoid liquidation; use a **Limit close** in the Close tab when you have a target price and aren't in a rush. ## Related Articles * [Adjusting Margin & Leverage](/perpetual-trading/position-management/adjusting-margin-and-leverage) * [Understanding PnL](/perpetual-trading/pnl) # Position Management Source: https://docs.yellow.pro/perpetual-trading/position-management/overview Actively manage your open perpetual positions on Yellow.pro — adjust margin, change leverage, and close positions fully or partially. This section covers how to manage your open perpetual positions: adjusting your margin buffer, changing leverage, and closing positions fully or partially. ## In This Section Add margin and change leverage, and how each affects your liquidation price. Close fully or partially, and what happens to margin and realized PnL. # Cross-Margin Risk & ADL Source: https://docs.yellow.pro/perpetual-trading/risk-and-liquidation/cross-margin-risk-and-adl How cross margin aggregates risk across all your positions, and how auto-deleveraging (ADL) settles liquidations against opposing traders. ## How Cross Margin Aggregates Risk Yellow\.pro uses **cross margin**, so all positions share one pool of collateral — your total account balance. Liquidation is assessed on your **entire account**, not a single position: `Account Equity = Total Balance + Total Unrealized PnL` `Margin Ratio = Total Maintenance Margin Required / Account Equity` Liquidation occurs when the total-account margin ratio reaches 100%. > **Example:** a long ETH down −300 USDT and a short BTC up +100 USDT net to −200 USDT. If the ETH loss grows, the combined margin ratio can trigger liquidation — even though the BTC short is profitable. ### The cascade effect In extreme conditions, one position's losses can threaten the whole account: the market moves sharply against position A → account equity drops → the account margin ratio rises → if it hits 100%, **all positions may be liquidated, including profitable ones.** This is the main risk of cross margin. **Protective measures:** use a stop-loss on every position, size positions so no single trade dominates, keep free margin well above zero, and monitor your margin ratio in volatile markets. ## Auto-Deleveraging (ADL) When an account is liquidated, its positions are matched against **real opposing positions** held by other traders. This matching mechanism is **Auto-Deleveraging (ADL)** — a liquidation and an ADL are two sides of the same trade. ### How ADL works 1. An account is liquidated and its remaining position is taken over for settlement. 2. The ADL engine ranks traders on the **opposite side** of that market by a priority score combining **profit and position size** (higher unrealized profit relative to size = higher priority). 3. Top-ranked counterparties have part of their position closed to absorb the liquidated position. The match settles at the liquidated account's **liquidation price**, falling back to its **bankruptcy price** if the liquidation price can't be applied. 4. Affected traders are notified and can re-enter the market immediately. ### Managing ADL risk Your ADL priority rises with **high unrealized profit and high leverage** on a position. If you're holding a large, highly profitable, highly leveraged position, part of it may be used to close out a liquidated trader on the opposite side. To lower the chance of being deleveraged, take some profit (partially close) or reduce leverage. Being ADL'd isn't a fee or a penalty — it's the natural other side of a liquidation. Part of your **winning** position is closed early to absorb a liquidated trader, and you bank the profit on that portion at the settlement price. Because that price comes from the liquidated account rather than the current mark, the amount can differ slightly from closing at market yourself. The rest of your position stays open. ## Related Articles * [Liquidation & Mark Price](/perpetual-trading/risk-and-liquidation/liquidation-and-mark-price) * [Margin Warnings & Risk Management](/perpetual-trading/risk-and-liquidation/margin-warnings-and-risk-management) * [Margin & Leverage](/perpetual-trading/margin-and-leverage) # Liquidation & Mark Price Source: https://docs.yellow.pro/perpetual-trading/risk-and-liquidation/liquidation-and-mark-price What triggers liquidation on Yellow.pro, the liquidation process and price, and why the mark price (not the last traded price) determines it. ## What is Liquidation? **Liquidation** is the automatic closure of one or more open positions when your account no longer has sufficient margin to support them. It prevents your balance from going negative. You lose the margin allocated to the affected position(s), but never owe more than you deposited. ## When Does Liquidation Happen? Liquidation triggers when your **Margin Ratio reaches 100%** — your account equity has dropped to the maintenance margin level: `Margin Ratio = Maintenance Margin Required / Account Equity` In **cross margin mode** (used on Yellow\.pro), this is calculated across **all** your open positions together, not per individual position. The **Maintenance Margin Rate (MMR)** is the fraction of position notional you must keep as a buffer. On current markets (BTC and ETH perpetuals) the MMR is a flat **0.5%**: `Maintenance Margin Required = Position Notional × 0.5%` To protect you from brief price wicks, liquidation is evaluated on the **worst-case mark price** seen in each scan window — the lowest price for longs and the highest for shorts — not on a single instantaneous tick. ## The Liquidation Process 1. **Detection** — the system continuously monitors your account's margin ratio. 2. **Trigger** — when the ratio hits 100%, the liquidation engine takes over your account. 3. **Netting** — if you hold both a long and a short in the same market, they are closed against each other first to reduce exposure. 4. **Takeover & settlement** — your remaining position(s) are taken over and matched against opposing traders through [auto-deleveraging (ADL)](/perpetual-trading/risk-and-liquidation/cross-margin-risk-and-adl), settled at your **Liquidation Price** (or the **Bankruptcy Price** as a fallback — both explained below). 5. **Record** — the liquidation is logged in your Trade History. A liquidation entry in trade history When a position breaches its maintenance margin, Yellow\.pro doesn't immediately seize the whole thing. It first attempts a **graduated reduction** — closing your position in steps — to preserve as much of your capital as possible. Full takeover only happens if these steps aren't enough. Here's how the smart-liquidation engine works: Instead of seizing the entire position at once, the engine places a **partial close order at the bankruptcy price**, reducing your position size in steps. The reduction amount is sized according to the position's **risk tier**, so larger positions reduce in proportionally appropriate increments. After each partial close, the engine re-evaluates whether full liquidation is still necessary. **If your margin is restored, the position survives** at a smaller size. Reduction steps respect the market's minimum order size. If the default step is too small to trade, the engine automatically escalates to a tradeable size. Tiered reduction is designed to give your position the best chance of surviving a margin breach at a smaller size. It happens automatically — there's nothing to configure — but the best protection is still to manage margin and leverage before the maintenance level is reached. ## Liquidation Price Your **Liquidation Price** is the estimated Mark Price at which your account would be liquidated — the price at which your equity falls to the maintenance margin level. It's shown in the positions panel. In cross margin it is **not fixed**: it moves with your unrealized PnL, positions you open or close, and deposits or withdrawals. For a single position with balance `B`, the simplified formula is: ``` Long: Liquidation Price = (Amount × Entry − B) / (Amount × (1 − MMR)) Short: Liquidation Price = (Amount × Entry + B) / (Amount × (1 + MMR)) ``` In practice the engine also folds in the unrealized PnL and maintenance margin of your *other* open positions, since cross margin shares one collateral pool. You don't need to compute this by hand — the platform displays your live liquidation price — but the formula shows what moves it. You open a long of **0.1 BTC at 50,000**, with a balance of **1,000 USDT** and no other positions. At MMR = 0.5%: `(0.1 × 50,000 − 1,000) / (0.1 × (1 − 0.005)) = 4,000 / 0.0995 ≈ 40,201` Your liquidation price is about **40,201**. Adding margin lowers it; opening more positions or taking losses elsewhere raises it. ## Bankruptcy Price The **Bankruptcy Price** is the Mark Price at which your account equity reaches **zero**. It sits *beyond* your liquidation price (lower for a long, higher for a short) — liquidation is triggered first, leaving a thin buffer before bankruptcy. ``` Long: Bankruptcy Price = Entry − (Account Equity / Position Size) Short: Bankruptcy Price = Entry + (Account Equity / Position Size) ``` A liquidation normally settles at your liquidation price. The bankruptcy price is the **fallback** used when the liquidation price can't be applied — it's the worst-case floor for what a position can settle at. Any value between your liquidation price and bankruptcy price is consumed by the liquidation; whatever remains (often little or nothing) stays in your balance. ## Mark Price vs Last Traded Price Yellow\.pro shows two prices, and the difference matters: * **Last Traded Price** — the price of the most recent trade. It can be briefly distorted by large orders or thin liquidity. * **Mark Price** — a calculated fair-value price derived from external reference data that smooths out temporary anomalies. **Liquidation and unrealized PnL are based on the Mark Price**, not the last traded price. This protects you both ways: a temporary spike in the last traded price that doesn't move the Mark Price will **not** liquidate you — but a drop in the Mark Price that isn't visible on the chart **can**. Always watch the Mark Price in your positions panel. ## How to Avoid Liquidation * Set **stop-loss orders** to exit before the liquidation threshold (not guaranteed). * **Add margin** (deposit funds) to increase your buffer. * **Reduce position size or leverage** to lower the maintenance margin required. * **Monitor your margin ratio** and act early. Make sure [margin warning emails](/perpetual-trading/risk-and-liquidation/margin-warnings-and-risk-management) are enabled. ## Related Articles * [Cross-Margin Risk & ADL](/perpetual-trading/risk-and-liquidation/cross-margin-risk-and-adl) * [Margin Warnings & Risk Management](/perpetual-trading/risk-and-liquidation/margin-warnings-and-risk-management) * [Margin & Leverage](/perpetual-trading/margin-and-leverage) # Margin Warnings & Risk Management Source: https://docs.yellow.pro/perpetual-trading/risk-and-liquidation/margin-warnings-and-risk-management What margin warning emails mean and how to enable them, plus core risk-management principles for leveraged trading. ## Margin Warning Emails Yellow\.pro sends **margin warning emails** when your margin ratio rises above a warning threshold — before it reaches the 100% liquidation point. It's an early alert giving you time to act. ### What to do when you receive one **Act immediately.** A margin warning can escalate to liquidation within minutes. 1. **Log in** at [yellow.pro](https://yellow.pro). 2. **Check your margin ratio** and open positions in the positions panel. 3. **Add funds** — in cross margin this immediately increases the buffer for all positions. 4. **Reduce exposure** — partially or fully close at-risk positions, place stop-losses, or lower leverage. 5. **Monitor** until the situation stabilises. ### How to enable margin warning emails Margin warnings are sent to the email linked to your account. **Your email is never linked automatically — no matter how you signed in, you must link it manually.** Until you link and verify an email, no margin warning emails are sent. To link it, go to `yellow.pro/settings` → **Linked Socials** → **Link** next to Email, then verify it. Linking an email to receive liquidation and margin-warning notifications If you haven't linked and verified an email, you will **not** receive any margin warning alerts — regardless of your login method. Link one as soon as possible. ## Risk Management Basics Effective risk management is the difference between long-term trading and rapid account depletion. 1. **Only risk what you can afford to lose** — set a max risk per trade and per session. 2. **Use stop-loss orders on every position** — set them before opening, at the level where your thesis is wrong (not at the liquidation price). 3. **Control your leverage** — beginners 1x–3x, intermediate 3x–10x, advanced 10x+ with strict controls. 4. **Size positions appropriately** — risk only a small percentage (e.g. 1–2%) of your balance per trade. 5. **Monitor your margin ratio** — below 50% is generally safe; 75%+ is high risk; 100% triggers liquidation. 6. **Don't chase losses** — avoid revenge-trading after a loss. 7. **Take profits regularly** — unrealized profit isn't yours until you close. 8. **Understand the market** — know volatility, key levels, and upcoming events. 9. **Keep a trading journal** — record entries, exits, size, leverage, and reasoning. ## Related Articles * [Liquidation & Mark Price](/perpetual-trading/risk-and-liquidation/liquidation-and-mark-price) * [Cross-Margin Risk & ADL](/perpetual-trading/risk-and-liquidation/cross-margin-risk-and-adl) * [Margin & Leverage](/perpetual-trading/margin-and-leverage) # Risk & Liquidation Source: https://docs.yellow.pro/perpetual-trading/risk-and-liquidation/overview How liquidation works on Yellow.pro perpetuals — mark price, cross-margin risk, ADL, margin warnings, and how to manage risk. Perpetual trading is leveraged, so understanding liquidation is essential. This section explains what triggers liquidation, how the mark price and cross-margin model affect it, what auto-deleveraging (ADL) is, and how to keep your account safe. Liquidation closes your position automatically when your account can no longer meet maintenance margin. You can never lose more than your deposited balance — Yellow\.pro does not issue margin calls for additional funds. ## In This Section What triggers liquidation, the process, and why mark price (not last price) decides it. How shared collateral aggregates risk, and how auto-deleveraging settles liquidations. Warning emails and practical risk-management principles. # What is Perpetual Trading? Source: https://docs.yellow.pro/perpetual-trading/what-is-perpetual-trading Perpetual trading on Yellow.pro — speculate on crypto prices with leverage, long or short, without owning the underlying asset. Perpetual trading involves significant risk, including the possibility of losing more than your initial margin. Only trade with funds you can afford to lose. Perpetual trading lets you speculate on the price of cryptocurrencies **without owning the underlying asset**. You trade a **perpetual contract** that tracks the market price of an asset like BTC or ETH. Unlike traditional futures, perpetual contracts have **no expiry date** — your position stays open until you close it or it is liquidated. ## How Perpetual Contracts Work * **No asset ownership** — you never actually hold BTC, ETH, or any other coin. * **Leverage** — you can control a position much larger than your deposited funds. * **Mark Price** — positions are valued using the [Mark Price](/perpetual-trading/risk-and-liquidation/liquidation-and-mark-price), designed to reflect fair value and reduce manipulation. * **Liquidation** — if the market moves against you beyond your margin buffer, your position is closed automatically. * **Order types** — perpetual orders use the same **market, limit, and stop** types and **Time in Force** options as spot. See [Order Types](/spot-trading/order-types). ## Perpetual vs Spot — Key Differences | | Spot | Perpetual | | ----------------------- | -------------------- | -------------------- | | You own the asset | Yes | No | | Leverage | No | Yes | | Profit in a bear market | No (only by selling) | Yes (by going short) | | Expiry | N/A | No expiry | | Liquidation risk | None | Yes | | Complexity | Lower | Higher | ## Who Should Use Perpetual Trading? Perpetual trading is designed for traders who want to speculate on short-term price movements, hedge existing spot positions, and are comfortable with the risks of leverage and liquidation. New to trading? Start with [What is Spot Trading?](/spot-trading/what-is-spot-trading) first. ## Related Articles * [Order Types](/spot-trading/order-types) * [Long, Short & Hedge Mode](/perpetual-trading/long-short-hedge-mode) * [Margin & Leverage](/perpetual-trading/margin-and-leverage) * [Risk & Liquidation](/perpetual-trading/risk-and-liquidation) # Overview Source: https://docs.yellow.pro/portfolio/overview General guide about your Portfolio Understanding how to navigate the section * [Portfolio Overview](/portfolio/portfolio-overview) * [Position History](/portfolio/position-history) # Portfolio Overview Source: https://docs.yellow.pro/portfolio/portfolio-overview A single, consolidated view of your entire Yellow.pro account. Spot and perpetual equity side by side, with the metrics that matter at a glance. The Portfolio Overview page brings your whole account into one screen so you can see your total value, this month's performance, and how much risk you're carrying, without switching between the Spot and Perpetual views. ## Unified Equity Display Your **total equity** is shown across both your Spot and Perpetual accounts, broken down by asset class and updated in real time. This is the single number that answers "how much is my account worth right now?", combining available balances, funds in open orders, and the value of open perpetual positions. ## Monthly Performance A set of key performance indicators (KPIs), all scoped to the **current calendar month**, so you can track how you're doing without the noise of older activity: * **Realized PnL** — profit or loss from positions you've already closed this month. * **Unrealized PnL** — current profit or loss on positions still open. * **Net funding** — funding fees paid or received on your perpetual positions. * **Open positions** — how many positions you currently hold. * **Leverage in use** — how much leverage your open positions are applying. * **Win rate** — the percentage of your closed positions this month that were profitable. Monthly KPIs reset at the start of each calendar month. To review activity from previous months, use the [Position History](/portfolio/position-history) tab. ## Risk Snapshot Alongside your perpetual overview, the page shows your **cross-margin ratio** and **maintenance margin** so you can see how close you are to liquidation before it happens. Watching these two figures is the simplest way to stay ahead of margin risk. For a full explanation of how these values are calculated, see [Cross-Margin Risk & ADL](/perpetual-trading/risk-and-liquidation/cross-margin-risk-and-adl). ## Win-Rate Tracking Every closed position is automatically classified as **winning** or **losing**, and the page keeps a rolling **win-rate percentage** for the month. This gives you an at-a-glance sense of how consistently your closed trades are working out, independent of the size of any single trade. ## Related Articles * [Position History](/perpetual-trading/position-management) * [Understanding Your Balances](/account-and-balance/understanding-your-balances) * [Understanding PnL](/perpetual-trading/pnl) * [Cross-Margin Risk & ADL](/perpetual-trading/risk-and-liquidation/cross-margin-risk-and-adl) # Position History Source: https://docs.yellow.pro/portfolio/position-history A dedicated history tab for your **closed perpetual positions**, with full trade-level drill-down. Use it to review how a position performed, why it closed, and every fill that went into it. ## The Closed-Position List Position History lists every closed perpetual position with the details you need to review a trade at a glance: * **Entry and exit price** — the average prices at which the position was opened and closed. * **Realized PnL** — the final profit or loss, after fees. * **Total fees** — trading fees paid across the life of the position. * **PnL ratio** — your realized PnL as a percentage of the margin committed. * **Close reason** — how the position ended: * **Normal close** — you closed it yourself (fully or partially). * **Liquidation** — it was closed by the liquidation engine. * **Auto-deleveraging (ADL)** — it was closed as a counterparty to another account's liquidation. ## Filtering & Sorting Find specific positions quickly: * **Filter by market** — narrow the list to a single perpetual symbol (e.g. BTC-PERP). * **Filter by open time or close time** — restrict to a date range. * **Sort by open date or close date** — order the list by when positions were opened or closed. ## Browsing Long Histories Position History uses **cursor-based pagination**, so you can scroll smoothly through thousands of historical positions without hitting page limits or losing your place. ## Per-Fill Detail View Open any closed position to see the **individual fills** that built and closed it. Each fill shows: * **Direction** — buy or sell. * **Size** — the amount filled. * **Price** — the execution price of that fill. * **Fee** — the fee charged on that fill. * **Execution type** — how the fill occurred: * **Trade** — a normal match against the order book. * **Liquidation** — a fill created by the liquidation engine. * **Takeover** — a fill created when the position was taken over during liquidation or ADL. A single position can contain many fills — for example, a large order that filled in pieces, plus the fills that later closed it. The per-fill view is the most granular record of exactly how a position was executed. ## Related Articles * [Portfolio Overview](/portfolio/portfolio-overview) * [Closing a Position](/perpetual-trading/position-management/closing-a-position) * [Risk & Liquidation](/perpetual-trading/risk-and-liquidation) * [Cross-Margin Risk & ADL](/perpetual-trading/risk-and-liquidation/cross-margin-risk-and-adl) # FAQ Source: https://docs.yellow.pro/spot-trading/faq Quick answers to common spot trading questions on Yellow.pro. For full detail, see [Order Types](/spot-trading/order-types) (market, limit, and stop orders) and [Managing Orders](/spot-trading/managing-orders) (open orders, history, statuses, cancellations, and rejections). A **market order** executes immediately at the best price currently available — you don't choose a specific price. A **limit order** lets you specify the exact price at which you want to buy or sell, and only fills at that price or better; if no matching liquidity exists, it stays open until filled or cancelled. Market orders prioritise speed; limit orders prioritise price control. See [Order Types](/spot-trading/order-types). A stop limit order activates only when the market reaches your **trigger price**, then places a **limit order** at your defined limit price. Set the trigger price (when it activates) and the limit price (the price of the resulting order). Because a limit order is placed after the trigger, there's no guarantee of execution if the market moves quickly past your limit price. See [Order Types](/spot-trading/order-types). A stop market order also activates at a trigger price, but submits a **market order** immediately upon activation instead of a limit order. Use stop **market** when you want to ensure execution after the trigger; use stop **limit** when you want to control the worst price you'll accept. See [Order Types](/spot-trading/order-types). When you place an order, Yellow\.pro locks the funds needed to fill it — buy orders lock the quote currency (e.g. USDT), sell orders lock the base currency (e.g. BTC or ETH). They show as **In Orders** and return to **Available** when the order is filled, cancelled, or rejected. (Funds for a withdrawal that's still processing also show as In Orders.) This stops you from spending the same funds twice. **Open Orders** — currently active orders waiting to be filled or cancelled. **Order History** — a log of all orders placed (filled, partially filled, cancelled, or rejected). **Trade History** — a record of every actual fill. An order can appear in Order History with no Trade History entry if it was cancelled or rejected before filling. See [Managing Orders](/spot-trading/managing-orders). A **maker** places an order that rests in the book and adds liquidity (typically a limit order that doesn't fill immediately). A **taker** matches an existing order immediately and takes liquidity (always the case for market orders, and for limit orders that cross the spread). See [Fees](/fees/trading-fees) for how this affects your rate. # How to Place a Spot Trade Source: https://docs.yellow.pro/spot-trading/how-to-place-a-spot-trade A step-by-step guide to placing and cancelling a spot trade on Yellow.pro. ## Before You Start Make sure you have: * connected your wallet and logged in to [Yellow.pro](https://yellow.pro) * deposited funds into your account * sufficient **Available** balance in the relevant currency > If part of your balance shows as **In Orders**, those funds are locked by open orders (or a withdrawal in progress). Cancel an open order to release them. On the left panel of the trading interface, browse or search for the market you want to trade (for example, `ETH-USDT`). The order book, chart, and order form load for that market. Selecting a market on the Yellow.pro trading interface In the order form, select your order type: * **Market order** — executes immediately at the best available price. No price input needed. * **Limit order** — executes at your specified price or better. Requires a price input. * **Stop Limit / Stop Market** — conditional orders that activate when a trigger price is reached. The order form with the order-type selector Not sure which to choose? See [Order Types](/spot-trading/order-types). * **Buy ETH-USDT** → you spend USDT to receive ETH. * **Sell ETH-USDT** → you spend ETH to receive USDT. * **Market order:** enter only the **Amount**; the platform uses the best available price. * **Limit order:** enter both the **Price** and the **Amount**. The form shows an estimated **total value** before you confirm. > Ensure your price respects the market's **tick size** and your amount respects the **step size**, or the order will be rejected. See [Market Rules & Limits](/spot-trading/market-rules) for each market's values. Double-check the market, side, order type, price (if applicable), amount, and estimated fee, then click **Buy** or **Sell**. After submission: * your order appears in **Open Orders** at the bottom of the screen * if it fills immediately, your balance updates and the trade appears in **Trade History** * if it's a limit order waiting to be filled, it stays in **Open Orders** until matched or cancelled **Open order:** An open order shown in the Open Orders panel **Filled order:** A filled order shown in trade history ## Cancelling an Open Order 1. Go to the **Open Orders** tab at the bottom of the screen. 2. Find the order you want to cancel. 3. Click the **Cancel** (X) button next to it. Funds held **In Orders** for the cancelled order return to your **Available** balance immediately. Cancelling an open order from the Open Orders tab ## Tips for New Traders * Start with small amounts while you get familiar with the interface. * Use limit orders when you care about the exact execution price. * Always verify your order details before confirming — there is no undo after submission (though you can cancel a limit order if it hasn't filled yet). * Check market parameters (tick size, minimum size) if your order is being rejected. ## Related Articles * [Order Types](/spot-trading/order-types) * [Managing Orders](/spot-trading/managing-orders) * [Market Rules & Limits](/spot-trading/market-rules) # Managing Orders Source: https://docs.yellow.pro/spot-trading/managing-orders Track your activity with Open Orders, Order History, and Trade History, understand the In Orders balance, and fix common order rejections. Yellow\.pro provides three views to track your trading activity — **Open Orders**, **Order History**, and **Trade History** — plus clear rejection reasons when an order fails validation. ## Open Orders Shows all orders currently **active in the order book** — submitted but not yet filled or cancelled. Here you'll see orders waiting for the market to reach your limit price, and triggered conditional orders that are now live. You can **cancel** any open order at any time; the funds held **In Orders** are released back to **Available** immediately. The Open Orders panel ## Order History A full log of all orders you've placed, regardless of outcome: | Status | Meaning | | ---------------- | ---------------------------------------------------------------- | | Filled | The order was completely matched and executed. | | Partially Filled | Some, but not all, of the order was executed. | | Cancelled | You or the system cancelled the order before it fully filled. | | Rejected | The order failed validation and was never placed in the book. | | Expired | The order expired due to time-in-force settings (e.g. IOC, FOK). | Check Order History to confirm an order's status, investigate why an order didn't fill, or review a rejection reason. The Order History view ## Trade History (Fill History) Records only actual **executions** — moments when your order matched another and a trade occurred. Each entry shows the timestamp, market and side, fill price and quantity, and the fee charged. **Key difference:** an order in Order History may have **zero fills** (if cancelled or rejected). Trade History only shows orders that actually executed. A partial fill produces one Order History entry and one or more Trade History entries. The Trade History (fill history) view ## Balances: Total, Available & In Orders | Balance type | Meaning | | ------------- | ---------------------------------------------------------------------------------- | | **Total** | All funds in your account (Available + In Orders). | | **Available** | Funds you can use right now — for new orders or withdrawals. | | **In Orders** | Funds locked for active open orders and for withdrawals that are still processing. | > **Example:** you have 1,000 USDT and place a buy limit for 500 USDT of ETH. Your balance shows **Total: 1,000 · Available: 500 · In Orders: 500**. When the order fills or you cancel it, the In Orders amount returns to Available. Buy orders reserve the **quote** currency (e.g. USDT); sell orders reserve the **base** currency (e.g. BTC or ETH). This prevents you from spending the same funds on multiple orders at once. ## Why Was My Order Rejected? A rejected order failed one or more validation checks and appears in Order History with a reason. For the exact tick size, step size, and limits per market, see [Market Rules & Limits](/spot-trading/market-rules). Common causes: * **Price not aligned with tick size** — round your price to a valid increment (e.g. with tick size 0.10, `2,100.05` is invalid). * **Size not aligned with step size** — adjust your quantity to a valid increment. * **Below minimum order size** — increase the quantity. * **Below minimum order value** (price × size) — increase price or quantity to meet the minimum. * **Limit price outside the price band** — your limit price is more than 25% from the current market price; move it closer. * **Insufficient available balance** — funds already committed to other open orders (shown as In Orders) don't count; cancel orders or deposit more. * **Invalid trigger settings** — for stop orders, ensure the trigger price is on the correct side of the market and required fields are set. * **Market temporarily unavailable** — wait and retry; contact support if it persists. ### Checklist before placing an order * Correct market and side (Buy vs Sell) * Price aligned with tick size (limit orders) * Limit price within 25% of the current market price * Amount aligned with step size * Total order value meets the minimum * Available balance is sufficient * Trigger settings correct (stop orders) ## Why Was My Order Not Executed? * **Limit price not reached** — the market never traded at your price. * **Insufficient liquidity** — not enough in the book to fill at your price. * **Cancelled** — by you, or by time-in-force settings (IOC/FOK that couldn't fill). * **Rejected** — see the reasons above. Check your Order History for the status and reason of any unfilled order. If everything looks correct and orders still fail, [contact support](/community-and-resources/contact-support) with the market, your order details, and a screenshot of the rejection reason. ## Related Articles * [How to Place a Spot Trade](/spot-trading/how-to-place-a-spot-trade) * [Order Types](/spot-trading/order-types) * [Market Rules & Limits](/spot-trading/market-rules) # Market Rules & Limits Source: https://docs.yellow.pro/spot-trading/market-rules Spot market trading rules — tick size, step size, minimum order size and value, price band, and slippage tolerance — and why an order might not be accepted. Every spot order is checked against the rules of its market **before it's accepted**. An order that breaks any rule is **not created** — the platform blocks it at submission, so it never enters the order book or your Order History. **If you're unable to place an order, one of the rules below is the most likely reason.** This page lists the rules and the current values for each spot market. ## Order Validation Rules | Rule | What it means | You can't place the order if… | | ---------------------- | -------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- | | **Tick size** | The smallest allowed price increment. Your price must be an exact multiple of it. | Price is not a multiple of the tick size. | | **Step size** | The smallest allowed amount increment. Your amount must be an exact multiple of it. | Amount is not a multiple of the step size. | | **Minimum order size** | The smallest amount (in the base asset) you can trade. | Amount is below the minimum. | | **Maximum order size** | The largest amount (in the base asset) per order. | Amount is above the maximum. | | **Minimum notional** | The smallest order *value* (price × amount, in USDT). | Order value is below the minimum notional. | | **Price band** | A limit order's price must stay within a percentage band around the current reference price. | A limit (or trigger) price is more than **25%** above or below the reference price. | | **Available balance** | You must have enough Available balance (not already committed In Orders) to cover the order. | Available balance is insufficient. | > Market orders aren't subject to a placement rule for slippage — they execute immediately, with a protective cap on spend. See [Market-order slippage tolerance](#market-order-slippage-tolerance) below. ## Spot Market Specifications Prices and amounts accept up to 8 decimal places, but must still align to the **tick size** (price) and **step size** (amount) below. | Market | Min order | Max order | Step size | Tick size | Min notional | | -------------- | ----------- | ----------------- | --------- | --------- | ------------ | | **WBTCUSDT** | 0.0001 WBTC | 50,000 WBTC | 0.0001 | 0.01 | 1 USDT | | **ETHUSDT** | 0.001 ETH | 50,000 ETH | 0.001 | 0.01 | 1 USDT | | **YELLOWUSDT** | 1 YELLOW | 10,000,000 YELLOW | 1 | 0.0001 | 5 USDT | All spot markets currently apply a **±25% price band** on limit and trigger orders — the price must stay within 25% of the current market price, so the allowed range moves with the market. ## Market-order slippage tolerance A market order executes immediately at the best available prices, so its average fill price can differ from the submission price. A market **buy** keeps your total spend within about **5%** of the expected amount; if the price moves further, the order fills only up to that limit. Market **sells** are unaffected, since they lock the exact amount you're selling. ## Worked Examples You place a limit buy on **ETHUSDT** at **2,000.005**. The tick size is **0.01**, so the price must end at a multiple of 0.01 (e.g. `2,000.00` or `2,000.01`). You won't be able to place it — round your price to the tick size and try again. You try to sell **0.0005 ETH**. The minimum order size on ETHUSDT is **0.001** and the step size is **0.001**, so `0.0005` is both too small and not a valid increment. Use `0.001`, `0.002`, and so on. You place a buy on **YELLOWUSDT** for **3 YELLOW** at **0.50 USDT** — an order value of `1.5 USDT`. The minimum notional is **5 USDT**, so the order can't be placed. Increase the amount or price so the total value is at least 5 USDT. With ETH trading around **3,000 USDT**, you place a limit buy at **2,200**. That's more than **25%** below the reference price (the floor is `3,000 × 0.75 = 2,250`), so it's blocked. Place your limit price within 25% of the current price — between **2,250** and **3,750** in this example. ## Related Articles * [How to Place a Spot Trade](/spot-trading/how-to-place-a-spot-trade) * [Order Types](/spot-trading/order-types) * [Managing Orders](/spot-trading/managing-orders) # Order Types Source: https://docs.yellow.pro/spot-trading/order-types Market and limit orders, plus conditional orders (stop market and stop limit) on Yellow.pro — how each works and when to use it. Yellow\.pro supports **market** and **limit** orders, plus **conditional (stop) orders** that activate at a trigger price. The same order types and [Time in Force](#time-in-force-tif) options apply to both **Spot and Perpetual** markets (examples below use spot pairs). Understanding the difference helps you make better decisions and avoid unexpected outcomes. ## Market Order A market order is designed for **immediate execution**, filling against the best available prices in the order book. * **What you control:** the amount (quantity). * **What you don't control:** the exact price. **When to use:** you need to execute immediately, the exact price matters less than getting filled, and the market is liquid. **Risk — slippage:** in fast-moving or low-liquidity markets, your final fill price may differ from the price displayed at submission. This is normal and expected. ## Limit Order A limit order lets you **specify the exact price** at which you want to buy or sell. It only executes at that price or better. * **Buy limit:** the maximum price you'll pay. A buy limit at 2,050 USDT waits until a seller offers at 2,050 or below. * **Sell limit:** the minimum price you'll accept. A sell limit at 2,150 USDT only fills if a buyer pays 2,150 or above. If your limit price matches existing orders already in the book, the order may fill **immediately**, acting like a market order — this means you were taking available liquidity at your stated price, not an error. **When to use:** you want a specific price, you're not in a rush, and you want to avoid slippage. **Risk:** the order may never fill, and partial fills are possible. ### Market vs Limit — at a glance | | Market Order | Limit Order | | --------------- | ------------ | ------------------------------------------ | | Execution speed | Immediate | When price is matched | | Price control | None | Full | | Slippage risk | Yes | No (fills at your price or better) | | Guaranteed fill | Very likely | Not guaranteed | | Acts as | Always taker | Maker (if not filled immediately) or Taker | ## Conditional Orders (Stop Market & Stop Limit) Conditional orders **do not activate immediately**. They wait for the market to reach a specified **trigger price**, then automatically submit a new order. This lets you set up automated entry or exit strategies without watching the market continuously. The order form with a conditional (stop) order selected ### Stop Market Triggers at your trigger price, then submits a **market order** immediately. * **Fields:** trigger price, amount. * **Use it to:** cut losses if the market drops to a level (stop-loss), or enter when the market breaks a level — when execution matters more than exact price. * **Risk — gap:** the fill price may differ from your trigger price in fast-moving markets. ### Stop Limit Triggers at your trigger price, then submits a **limit order** at your specified limit price. * **Fields:** trigger price, limit price, amount. * **Use it to:** keep price control even after the trigger fires. * **Risk:** if the market moves quickly past your limit price, the order may **never fill**. ### Stop Market vs Stop Limit | | Stop Market | Stop Limit | | --------------------------- | ---------------------- | ----------------------- | | After trigger | Submits a market order | Submits a limit order | | Execution guarantee | High | Not guaranteed | | Price control after trigger | None | Yes | | Risk | Gap / slippage | Order may not fill | | Best for | Ensuring exit | Controlling worst price | Take Profit and Stop Loss must currently be created **manually** through the order form — they are not automatically linked to an existing position or order. After placing a TP/SL order, verify the trigger price, the order side, and that your available balance covers the order if it activates. Setting a Take Profit / Stop Loss order in the order form ## Time in Force (TIF) **Time in Force** controls how long an order stays active. Pick it from the **TIF** dropdown in the order form — it applies to both Spot and Perpetual orders. | TIF | Name | Behaviour | | ------- | ------------------- | -------------------------------------------------------------------------------------- | | **GTC** | Good 'Til Cancelled | Rests in the book until it fully fills or you cancel it. **Default for limit orders.** | | **IOC** | Immediate Or Cancel | Fills as much as possible right away; any unfilled remainder is cancelled. | | **FOK** | Fill Or Kill | Must fill **completely and immediately**, or the entire order is cancelled. | **Market orders are always IOC** — they execute immediately against available liquidity and cancel any unfilled remainder. The TIF selector applies to limit (and limit-style) orders, where **GTC is the default**. ## Maker vs Taker Your order type affects whether you are a **maker** or a **taker**: * **Taker** — your order consumes existing liquidity (market orders, or limit orders that fill immediately). * **Maker** — your order adds liquidity to the book and waits. See [Fees](/fees/trading-fees) for current maker and taker rates. ## Post only Orders A **post-only** order guarantees you are always a **maker** — and pay maker fees. It's designed for traders who want to add liquidity to the book and never cross the spread. * **Always a maker:** if the order would match against an order already resting in the book, it is **rejected** instead of filling. It can only rest as passive liquidity, so you never pay the taker fee. * **Spot and Perpetual:** post-only behaves the same way on both markets — submit, rest, and fill as a maker, or get rejected. * **Requires a limit price:** post-only always needs a limit price. There is no "market post-only", because a market order is inherently a taker order. **When to use:** you want to provide liquidity at a specific price and protect your maker-fee rate, and you'd rather have the order rejected than accidentally pay the taker fee. If your post-only order is rejected, it means your limit price would have matched immediately against the book. Adjust the price so it rests passively (above the best ask for a sell, below the best bid for a buy) and resubmit. * **Post-only** — guarantees maker status by rejecting any order that would fill immediately. See [Post-Only Order](#post-only-order) above. ## Related Articles * [How to Place a Spot Trade](/spot-trading/how-to-place-a-spot-trade) * [Managing Orders](/spot-trading/managing-orders) * [Fees](/fees/trading-fees) # Overview Source: https://docs.yellow.pro/spot-trading/overview Buy and sell crypto at market price on Yellow.pro. Learn how spot trading works and how to place and manage orders. The basics of spot markets. Step-by-step order placement. Market, limit, and conditional orders. Open orders, history, and rejections. Tick size, step size, limits, and why orders get rejected. Quick answers about spot trading. # What is Spot Trading? Source: https://docs.yellow.pro/spot-trading/what-is-spot-trading Spot trading on Yellow.pro — the direct exchange of one crypto asset for another at the current market price. Spot trading is the most straightforward way to trade on Yellow\.pro. It is the direct exchange of one cryptocurrency for another at the current market price — you buy or sell an asset and receive it immediately in your account balance. A spot market is always quoted as a pair, such as `ETH-USDT` or `BTC-USDT`, where: * the asset on the **left** is the **base currency** (what you are buying or selling) * the asset on the **right** is the **quote currency** (what you are paying or receiving) > **Example:** trading `ETH-USDT` means you are exchanging ETH and USDT. If you buy, you spend USDT to receive ETH. If you sell, you spend ETH to receive USDT. ## How Spot Trading Works on Yellow\.pro Yellow\.pro uses an **order book model** — when you place an order, it is matched against other traders' orders. When a spot order fills: 1. Your balance updates **immediately** on the platform after execution. 2. You can continue trading with your updated balance right away. 3. **No on-chain transaction occurs** for each trade. Assets only move on-chain when you **deposit** or **withdraw**. This means trading is fast and efficient — every trade settles internally, and blockchain fees only apply at deposit and withdrawal. ## What You Can Trade Yellow\.pro offers a variety of spot markets, browsable in the markets list on the left panel of the trading interface. Each market has its own parameters: * **Tick size** — the smallest price increment allowed * **Step size** — the smallest quantity increment allowed * **Minimum order size or value** — the smallest trade you can place * **Fee rate** — the cost of executing a trade ## Spot vs Perpetual Trading | | Spot | Perpetual | | ----------------- | ----------------------- | --------------------------------- | | What you trade | Actual assets | Contracts | | Leverage | No | Yes | | You own the asset | Yes | No | | Risk | Limited to your balance | Can exceed your balance | | Best for | Buying/holding crypto | Speculative or hedging strategies | If you are new to trading, spot is the recommended starting point. Perpetual trading involves additional complexity and risk. ## Related Articles * [How to Place a Spot Trade](/spot-trading/how-to-place-a-spot-trade) * [Order Types](/spot-trading/order-types) * [Managing Orders](/spot-trading/managing-orders)