{"openapi":"3.1.0","info":{"title":"Vanta Trading API","version":"1.0.0","summary":"Programmatic trading for Vanta prop accounts.","description":"REST endpoints for reading account state and placing orders on a\nVanta prop account. Keys are created in the dashboard under\nSettings → Key Management and are bound to a single account.\n\nEvery request carries four headers. The signature is\nHMAC-SHA256, base64-encoded, over the newline-joined canonical string:\n\n    v1\\n<METHOD>\\n<path + query>\\n<timestampMs>\\n<nonce>\\n<sha256hex(body)>\n\nThe timestamp must be within 5 minutes of server time and each nonce may be used\nonly once per key. See /docs/authentication for worked examples.","termsOfService":"https://www.vantatrading.io/terms-of-service"},"externalDocs":{"description":"Full documentation","url":"https://app.vantatrading.io/docs"},"servers":[{"url":"https://app.vantatrading.io","description":"Production"}],"tags":[{"name":"Trading","description":"Account state and order placement."}],"security":[{"VantaKeyId":[],"VantaTimestamp":[],"VantaNonce":[],"VantaSignature":[]}],"paths":{"/api/v1/trading/account":{"get":{"operationId":"getAccount","summary":"Account snapshot","description":"Consolidated account summary, current equity, status and evaluation, challenge progress, drawdown and performance. These are the same values shown on the dashboard.\n\nmeta.stale is true when the upstream validator was unavailable and values fell back to placeholders. Retry when you see it.\n\nchallenge.drawdownCriteria is \"trailing\" (legacy HWM rules) or \"static\" (limits measured against the starting account balance). For static accounts, challenge.drawdownBreakdown.highWaterMark carries the starting balance and the breakdown values reflect the static rules (5% balance / 5% EOD equity vs the starting balance).","tags":["Trading"],"x-required-scope":"trade:read","parameters":[{"name":"accountId","in":"query","required":false,"description":"Optional. The key is already bound to one account; when supplied this must match it, or the request is rejected with 403.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"accountId":{"type":"string"},"assetClass":{"type":"string"},"marketName":{"type":"string"},"accountSize":{"type":"number"},"formattedAccountSize":{"type":"string"},"evaluation":{"type":"object","properties":{"title":{"type":"string"},"status":{"type":"string"},"isEliminated":{"type":"boolean"},"accountSize":{"type":"string"},"activeAccounts":{"type":"string"},"effectiveAccountSizeNumeric":{"type":"number"}}},"account":{"type":"object","properties":{"currentBalance":{"type":"number"},"currentEquity":{"type":"number"},"balanceChange":{"type":"number"},"balanceChangePercent":{"type":"number"},"totalPnL":{"type":"number"},"totalPnLPercent":{"type":"number"},"openPnL":{"type":"number"},"openPnLPercent":{"type":"number"},"openPositions":{"type":"number"},"portfolioBalance":{"type":"number"},"portfolioBalanceChangePercent":{"type":"number"},"portfolioBalanceBreakdown":{"type":"object","properties":{"currentBalance":{"type":"number"},"marginLeverage":{"type":"number"},"sumPositionValue":{"type":"number"}}},"leverage":{"type":"string"},"capitalUsed":{"type":"number"},"totalRealizedPnl":{"type":"number"},"isPassed":{"type":"boolean"}}},"challenge":{"type":"object","properties":{"variant":{"type":"string"},"bucket":{"type":"string"},"drawdownCriteria":{"type":"string"},"profitTarget":{"type":"number"},"profitTargetPercent":{"type":"number"},"remaining":{"type":"number"},"maxLeverage":{"type":"string"},"trailingDrawdownPercent":{"type":"number"},"maxDrawdown":{"type":"number"},"daysRemaining":{"type":"number"},"totalDays":{"type":"number"},"drawdownBreakdown":{"type":"object","properties":{"highWaterMark":{"type":"number"},"allowedDrawdown":{"type":"number"},"currentDrawdown":{"type":"number"},"remainingDrawdown":{"type":"number"},"remainingDrawdownPercentHWM":{"type":"number"}}}}},"performance":{"type":"object","properties":{"totalTrades":{"type":"number"},"winRate":{"type":"number"},"totalWins":{"type":"number"},"avgTradePnL":{"type":"number"},"tradeDuration":{"type":"string"},"challengeStartMs":{"type":"number"},"dailyReturns":{"type":"array","items":{"type":"object","properties":{"date":{"type":"string"},"value":{"type":"number"}}}}}},"meta":{"type":"object","properties":{"generatedAtMs":{"type":"number"},"stale":{"type":"boolean"}}}}}}},"example":{"success":true,"data":{"accountId":"6f1c2e34-9a4b-4c1d-8e2f-1a2b3c4d5e6f","assetClass":"crypto","marketName":"Crypto","accountSize":25000,"formattedAccountSize":"25K","evaluation":{"title":"Crypto 25K Evaluation","status":"evaluation","isEliminated":false,"accountSize":"$25,000","activeAccounts":"1/1","effectiveAccountSizeNumeric":25000},"account":{"currentBalance":25120.5,"currentEquity":25180.25,"balanceChange":120.5,"balanceChangePercent":0.48,"totalPnL":180.25,"totalPnLPercent":0.72,"openPnL":59.75,"openPnLPercent":0.24,"openPositions":1,"portfolioBalance":25120.5,"portfolioBalanceChangePercent":0.48,"portfolioBalanceBreakdown":{"currentBalance":25120.5,"marginLeverage":5,"sumPositionValue":7202.5},"leverage":"Current - 0.2870x / Max - 10x","capitalUsed":7202.5,"totalRealizedPnl":120.5,"isPassed":false},"challenge":{"variant":"default","bucket":"SUBACCOUNT_CHALLENGE","drawdownCriteria":"trailing","profitTarget":2500,"profitTargetPercent":10,"remaining":2319.75,"maxLeverage":"10x","trailingDrawdownPercent":5,"maxDrawdown":-1250,"daysRemaining":27,"totalDays":90,"drawdownBreakdown":{"highWaterMark":25180.25,"allowedDrawdown":1259.01,"currentDrawdown":0,"remainingDrawdown":1259.01,"remainingDrawdownPercentHWM":5}},"performance":{"totalTrades":4,"winRate":75,"totalWins":3,"avgTradePnL":45.06,"tradeDuration":"63h 12m","challengeStartMs":1717200000000,"dailyReturns":[{"date":"2026-06-28","value":0.31},{"date":"2026-06-29","value":0.17}]},"meta":{"generatedAtMs":1717718400000,"stale":false}}}}}},"401":{"$ref":"#/components/responses/Error401"},"403":{"$ref":"#/components/responses/Error403"},"404":{"$ref":"#/components/responses/Error404"},"409":{"$ref":"#/components/responses/Error409"},"429":{"$ref":"#/components/responses/Error429"},"500":{"$ref":"#/components/responses/Error500"},"502":{"$ref":"#/components/responses/Error502"},"503":{"$ref":"#/components/responses/Error503"}}}},"/api/v1/trading/positions":{"get":{"operationId":"getPositions","summary":"Open positions","description":"Open positions in the current challenge bucket, including entry price, leverage, unrealized PnL and any attached TP/SL.","tags":["Trading"],"x-required-scope":"trade:read","parameters":[{"name":"accountId","in":"query","required":false,"description":"Optional. The key is already bound to one account; when supplied this must match it, or the request is rejected with 403.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"type":"object","properties":{"positionUuid":{"type":"string"},"tradePair":{"type":"string"},"tradePairDisplay":{"type":"string"},"positionType":{"type":"string"},"netLeverage":{"type":"number"},"averageEntryPrice":{"type":"number"},"currentReturn":{"type":"number"},"openMs":{"type":"number"},"unrealizedPnl":{"type":"number"},"realizedPnl":{"type":"number"},"netValue":{"type":"number"},"cumulativeEntryValue":{"type":"number"},"stopLoss":{"type":"number"},"takeProfit":{"type":"number"}}}}}},"example":{"success":true,"data":[{"positionUuid":"0f9d1a2b-3c4d-5e6f-7a8b-9c0d1e2f3a4b","tradePair":"BTCUSDC","tradePairDisplay":"BTC/USDC","positionType":"LONG","netLeverage":0.287,"averageEntryPrice":62450.12,"currentReturn":0.0024,"openMs":1717490000000,"unrealizedPnl":59.75,"realizedPnl":0,"netValue":7262.25,"cumulativeEntryValue":7202.5,"stopLoss":61000,"takeProfit":65000}]}}}},"401":{"$ref":"#/components/responses/Error401"},"403":{"$ref":"#/components/responses/Error403"},"404":{"$ref":"#/components/responses/Error404"},"409":{"$ref":"#/components/responses/Error409"},"429":{"$ref":"#/components/responses/Error429"},"500":{"$ref":"#/components/responses/Error500"},"502":{"$ref":"#/components/responses/Error502"},"503":{"$ref":"#/components/responses/Error503"}}}},"/api/v1/trading/orders":{"get":{"operationId":"getOrders","summary":"Pending orders","description":"Unfilled limit orders and per-position bracket legs (TP/SL) that will execute automatically.","tags":["Trading"],"x-required-scope":"trade:read","parameters":[{"name":"accountId","in":"query","required":false,"description":"Optional. The key is already bound to one account; when supplied this must match it, or the request is rejected with 403.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"type":"object","properties":{"orderUuid":{"type":"string"},"tradePair":{"type":"string"},"tradePairDisplay":{"type":"string"},"orderType":{"type":"string"},"executionType":{"type":"string"},"processedMs":{"type":"number"},"limitPrice":{"type":"number"},"leverage":{"type":"number"},"value":{"type":"number"},"quantity":{"description":"Nullable; null in the reference example."},"stopLoss":{"type":"number"},"takeProfit":{"type":"number"},"bracketPct":{"description":"Nullable; null in the reference example."},"trailingPercent":{"description":"Nullable; null in the reference example."},"trailingValue":{"description":"Nullable; null in the reference example."}}}}}},"example":{"success":true,"data":[{"orderUuid":"a12b3c4d-5e6f-7a8b-9c0d-1e2f3a4b5c6d","tradePair":"ETHUSDC","tradePairDisplay":"ETH/USDC","orderType":"LONG","executionType":"LIMIT","processedMs":1717500000000,"limitPrice":3200,"leverage":1,"value":1500,"quantity":null,"stopLoss":3100,"takeProfit":3500,"bracketPct":null,"trailingPercent":null,"trailingValue":null}]}}}},"401":{"$ref":"#/components/responses/Error401"},"403":{"$ref":"#/components/responses/Error403"},"404":{"$ref":"#/components/responses/Error404"},"409":{"$ref":"#/components/responses/Error409"},"429":{"$ref":"#/components/responses/Error429"},"500":{"$ref":"#/components/responses/Error500"},"502":{"$ref":"#/components/responses/Error502"},"503":{"$ref":"#/components/responses/Error503"}}},"post":{"operationId":"postOrders","summary":"Place an order","description":"Submit a market, limit or bracket order for the key's bound account. Also used to edit/cancel limit orders and flatten positions.\n\nexecution_type accepts MARKET, LIMIT, BRACKET, LIMIT_CANCEL, LIMIT_EDIT and FLAT_ALL.\n\nMutating endpoints cannot be run from the browser. Copy the signed script and run it from your terminal.","tags":["Trading"],"x-required-scope":"trade:place","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"accountId":{"type":"string"},"trade":{"type":"object","properties":{"execution_type":{"type":"string"},"trade_pair":{"type":"string"},"order_type":{"type":"string"},"value":{"type":"number"}}}}},"example":{"accountId":"6f1c2e34-9a4b-4c1d-8e2f-1a2b3c4d5e6f","trade":{"execution_type":"MARKET","trade_pair":"BTCUSDC","order_type":"LONG","value":1000}}}}},"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"status":{"type":"string"},"order_uuid":{"type":"string"}}}}},"example":{"success":true,"data":{"status":"accepted","order_uuid":"d45e6f7a-8b9c-0d1e-2f3a-4b5c6d7e8f90"}}}}},"400":{"$ref":"#/components/responses/Error400"},"401":{"$ref":"#/components/responses/Error401"},"403":{"$ref":"#/components/responses/Error403"},"404":{"$ref":"#/components/responses/Error404"},"409":{"$ref":"#/components/responses/Error409"},"429":{"$ref":"#/components/responses/Error429"},"500":{"$ref":"#/components/responses/Error500"}}}},"/api/v1/trading/trades":{"get":{"operationId":"getTrades","summary":"Trade history","description":"Closed/filled trades with entry & close price, realized PnL, return at close and fees.","tags":["Trading"],"x-required-scope":"trade:read","parameters":[{"name":"accountId","in":"query","required":false,"description":"Optional. The key is already bound to one account; when supplied this must match it, or the request is rejected with 403.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"tradePair":{"type":"string"},"tradePairDisplay":{"type":"string"},"positionType":{"type":"string"},"leverage":{"type":"string"},"positionSize":{"type":"string"},"entryPrice":{"type":"string"},"closePrice":{"type":"string"},"unrealizedPnl":{"type":"number"},"realizedPnl":{"type":"number"},"returnAtClose":{"type":"number"},"status":{"type":"string"},"openTimeMs":{"type":"number"},"closeTimeMs":{"type":"number"},"stopLoss":{"type":"number"},"takeProfit":{"type":"number"},"totalFees":{"type":"number"}}}}}},"example":{"success":true,"data":[{"id":"c34d5e6f-7a8b-9c0d-1e2f-3a4b5c6d7e8f","tradePair":"BTCUSDC","tradePairDisplay":"BTC/USDC","positionType":"LONG","leverage":"0.50x","positionSize":"$1,000.00","entryPrice":"$60,120.00","closePrice":"$61,540.00","unrealizedPnl":0,"realizedPnl":23.62,"returnAtClose":0.0236,"status":"Filled","openTimeMs":1717200000000,"closeTimeMs":1717230000000,"stopLoss":59000,"takeProfit":62000,"totalFees":1.18}]}}}},"401":{"$ref":"#/components/responses/Error401"},"403":{"$ref":"#/components/responses/Error403"},"404":{"$ref":"#/components/responses/Error404"},"409":{"$ref":"#/components/responses/Error409"},"429":{"$ref":"#/components/responses/Error429"},"500":{"$ref":"#/components/responses/Error500"},"502":{"$ref":"#/components/responses/Error502"},"503":{"$ref":"#/components/responses/Error503"}}}}},"components":{"securitySchemes":{"VantaKeyId":{"type":"apiKey","in":"header","name":"X-Vanta-Key-Id","description":"The key id shown when the key was created (`vk_…`)."},"VantaTimestamp":{"type":"apiKey","in":"header","name":"X-Vanta-Timestamp","description":"Whole milliseconds since the Unix epoch, as a decimal string. Must be within 5 minutes of server time."},"VantaNonce":{"type":"apiKey","in":"header","name":"X-Vanta-Nonce","description":"Unique random value per request. Single-use for the life of the key; replays are rejected with 409."},"VantaSignature":{"type":"apiKey","in":"header","name":"X-Vanta-Signature","description":"`v1=` followed by the base64 HMAC-SHA256 of the canonical string."}},"schemas":{"Error":{"type":"object","properties":{"error":{"type":"string","description":"Human-readable failure reason."},"required_scope":{"type":"string","description":"Present only on 403 insufficient_scope responses."}},"required":["error"],"example":{"error":"This API key is only valid for a different account"}}},"responses":{"Error400":{"description":"The order body failed validation. The message names the first problem found, such as an unknown execution_type, a malformed accountId, or a wrong field type. / Exactly one sizing field is required on MARKET and LIMIT orders. Sending none, or sending two, is rejected. / The account exists but has not finished provisioning on the trading network, so no orders can be routed to it.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"invalid-request":{"summary":"The order body failed validation. The message names the first problem found, such as an unknown execution_type, a malformed accountId, or a wrong field type.","value":{"error":"<field-specific validation message>"}},"missing-size":{"summary":"Exactly one sizing field is required on MARKET and LIMIT orders. Sending none, or sending two, is rejected.","value":{"error":"'leverage', 'value', or 'quantity' must be provided"}},"account-not-ready":{"summary":"The account exists but has not finished provisioning on the trading network, so no orders can be routed to it.","value":{"error":"Account is not ready for trading (missing subaccount_id)"}}}}}},"Error401":{"description":"One or more of the four auth headers is absent or empty. Note that all four are required on every request, including GETs. / X-Vanta-Timestamp is not a positive finite number. It is most often seconds since the epoch, an ISO date string, or a float. / The timestamp is more than 5 minutes away from server time in either direction. Usually a clock drift problem on the caller's machine, or a request that sat in a queue before being sent. / No active key matches X-Vanta-Key-Id: the key id is wrong, or the key has been revoked or deleted. / The HMAC did not match. The credential is recognised, so the fault is in the canonical string, the body hash, or the secret.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"missing-credentials":{"summary":"One or more of the four auth headers is absent or empty. Note that all four are required on every request, including GETs.","value":{"error":"Missing credentials"}},"invalid-timestamp":{"summary":"X-Vanta-Timestamp is not a positive finite number. It is most often seconds since the epoch, an ISO date string, or a float.","value":{"error":"Invalid timestamp"}},"timestamp-skew":{"summary":"The timestamp is more than 5 minutes away from server time in either direction. Usually a clock drift problem on the caller's machine, or a request that sat in a queue before being sent.","value":{"error":"Timestamp invalid"}},"invalid-key":{"summary":"No active key matches X-Vanta-Key-Id: the key id is wrong, or the key has been revoked or deleted.","value":{"error":"Invalid key"}},"bad-signature":{"summary":"The HMAC did not match. The credential is recognised, so the fault is in the canonical string, the body hash, or the secret.","value":{"error":"Bad signature"}}}}}},"Error403":{"description":"The key does not carry the scope the endpoint requires. The response also includes a required_scope field naming it. / Each key is bound to exactly one prop account. Either the ?accountId= query parameter or the accountId in the request body names a different one.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"insufficient-scope":{"summary":"The key does not carry the scope the endpoint requires. The response also includes a required_scope field naming it.","value":{"error":"insufficient_scope","required_scope":"trade:read"}},"wrong-account":{"summary":"Each key is bound to exactly one prop account. Either the ?accountId= query parameter or the accountId in the request body names a different one.","value":{"error":"This API key is only valid for a different account"}}}}}},"Error404":{"description":"The bound account no longer resolves for the key's owner. It was deleted, transferred, or never fully provisioned.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"account-not-found":{"summary":"The bound account no longer resolves for the key's owner. It was deleted, transferred, or never fully provisioned.","value":{"error":"Account not found"}}}}}},"Error409":{"description":"This nonce has already been used by this key. Nonces are stored permanently and are single use for the life of the key. This is the replay protection.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"nonce-replay":{"summary":"This nonce has already been used by this key. Nonces are stored permanently and are single use for the life of the key. This is the replay protection.","value":{"error":"Nonce"}}}}}},"Error429":{"description":"The per-key read budget for the current minute is exhausted. The response carries Retry-After plus X-RateLimit-Limit / -Remaining / -Reset. / The key accumulated 30 rejected requests within 10 minutes, so order placement is paused for a 15-minute cooldown. Retrying the same failing request in a loop is what triggers this.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}},"X-RateLimit-Limit":{"description":"Requests permitted per window. Present on read-budget 429s only.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests left in the current window. Present on read-budget 429s only.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix seconds at which the window resets. Present on read-budget 429s only.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"rate-limited":{"summary":"The per-key read budget for the current minute is exhausted. The response carries Retry-After plus X-RateLimit-Limit / -Remaining / -Reset.","value":{"error":"rate_limited"}},"too-many-failed-requests":{"summary":"The key accumulated 30 rejected requests within 10 minutes, so order placement is paused for a 15-minute cooldown. Retrying the same failing request in a loop is what triggers this.","value":{"error":"too_many_failed_requests"}}}}}},"Error500":{"description":"The stored key secret could not be decrypted server-side. This is a platform fault, not a problem with your request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"decrypt-failed":{"summary":"The stored key secret could not be decrypted server-side. This is a platform fault, not a problem with your request.","value":{"error":"Decrypt failed"}}}}}},"Error502":{"description":"The upstream trade-history service answered with an error rather than data.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"upstream-failure":{"summary":"The upstream trade-history service answered with an error rather than data.","value":{"error":"<upstream error message>"}}}}}},"Error503":{"description":"The upstream validator could not be reached. The endpoint fails closed on purpose: it will not return placeholder balances that a polling client would record as real account history.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"snapshot-unavailable":{"summary":"The upstream validator could not be reached. The endpoint fails closed on purpose: it will not return placeholder balances that a polling client would record as real account history.","value":{"error":"Account snapshot temporarily unavailable (PTN validator unreachable); retry shortly"}}}}}}}}}