On this page
Positions
GET /v1/positions returns the current open positions of an arbitrary
wallet, normalized to one cross-provider schema. It is BY-ADDRESS: the queried
wallet does not need to be bound to your org — the endpoint exists for
copy-trading (mirror) pollers watching a leader wallet. Auth is the
standard org bearer with the read scope, exactly like
/v1/portfolio.
Where /v1/portfolio answers "what is this wallet worth", /v1/positions
answers "what is this wallet holding right now" — per-position detail (size,
entry, leverage, liquidation price) instead of USD totals.
When to use this
- Copy-trading / mirroring — poll a leader's positions and diff against your follower account to compute the orders that re-sync the mirror.
- Position monitoring — alert on leverage, liquidation proximity, or new positions for any watched address.
- HIP-3 coverage — Hyperliquid positions are fanned out across the MAIN
perp dex AND every builder / HIP-3 dex, so
xyz:…-style positions are never missed.
Request
bashcurl -H "Authorization: Bearer art_live_<your-key>" \
"https://api.artery.questflow.ai/v1/positions?user=0x9d84cbc7eb19c4cbb24f3866c70a5fcab502d1dc"Query parameters
Address resolution is identical to /v1/portfolio:
| Parameter | Type | Required | Description |
|---|---|---|---|
user | string | conditional | Default EVM address (0x + 40 hex chars) applied to every provider without an override. Required unless a per-provider address (hlUser / pmUser) is given. Lowercased server-side. |
hlUser | string | no | Per-provider override for Hyperliquid — the leader's native HL account. Falls back to user. |
pmUser | string | no | Per-provider override for Polymarket — the deposit-wallet address. Falls back to user. |
provider | string | no | Comma-separated subset of polymarket, hyperliquid. Omit to fan out to every supported provider. |
Response
jsonc{
"user": "0x9d84cbc7eb19c4cbb24f3866c70a5fcab502d1dc",
"positions": [
{
"provider": "hyperliquid",
"dex": "", // '' = main perp dex; HIP-3 dexs by name
"coin": "BTC",
"szi": 0.0042, // signed size: positive long, negative short
"entryPx": 104250.0,
"positionValue": 441.21,
"unrealizedPnl": 3.42,
"leverage": { "type": "cross", "value": 20 },
"liquidationPx": 84210.5,
"marginUsed": 22.06,
},
{
"provider": "hyperliquid",
"dex": "xyz", // a HIP-3 / builder dex position
"coin": "xyz:SPCX",
"szi": -1.5,
"entryPx": 2.7,
"positionValue": 4.05,
"unrealizedPnl": -0.61,
"leverage": { "type": "isolated", "value": 3 },
"liquidationPx": null,
"marginUsed": 1.35,
},
{
"provider": "polymarket",
"conditionId": "0xdd22472e552920b8438158ea7238bfadfa4f736aa4cee91a6b86c39ead110917",
"outcome": "Yes",
"size": 120.5, // outcome-token shares
"avgPrice": 0.42,
"currentValue": 66.28,
"cashPnl": 15.67,
"title": "Will the SpaceX launch succeed?",
},
],
"providers": ["polymarket", "hyperliquid"],
"native": [
{
"provider": "hyperliquid",
"address": "0x9d84cbc7eb19c4cbb24f3866c70a5fcab502d1dc",
"native": {
"clearinghouseStateByDex": {
"": {
/* verbatim main-dex clearinghouseState */
},
"xyz": {
/* verbatim HIP-3 dex clearinghouseState */
},
},
},
},
{
"provider": "polymarket",
"address": "0x9d84cbc7eb19c4cbb24f3866c70a5fcab502d1dc",
"native": [
/* verbatim Polymarket data-api positions array */
],
},
],
"warnings": [],
"asOf": "2026-07-02T07:00:00.000Z",
}Semantics
- Normalized
positions[]— one entry per open position. Hyperliquid: one per coin per dex, fromclearinghouseState.assetPositions[]. Polymarket: one per outcome token held, from the data-api positions. Unknown / missing upstream fields degrade tonullrather than erroring — the raw values are always innative. dex(Hyperliquid) —''is the main perp dex; builder / HIP-3 dexs appear by name (their coins are prefixed, e.g.xyz:SPCX). The dex list comes from HLperpDexsso new builder dexs are picked up automatically.sziis the signed position size: positive = long, negative = short. Mirror engines should copy the sign, not just the magnitude.native[]— per-provider verbatim passthrough (HL keyed by dex underclearinghouseStateByDex; PM the raw positions array), so power users lose nothing to normalization.warnings[]— a provider (or a single HL dex) failing degrades to a warning; the call still returns200with whatever settled. Treat a warned provider as "stale, retry", never as "the leader is flat".asOf— when the server issued the fan-out.
Freshness & polling
Reads are live — clearinghouseState is intentionally uncached, so every
poll reflects current state; only slow-moving facts (the builder-dex list) are
briefly cached. Keep polling intervals ≥ 5 seconds per watched wallet to
stay inside the portfolio.read SKU quota and be a good citizen.
Error responses
| HTTP | error.code | When |
|---|---|---|
| 400 | validation_failed | No address given, or an address is not 0x-40-hex. |
| 400 | unknown_provider | provider= contains a name not in the supported set. |
| 401 | unauthenticated | Missing / invalid Authorization header. |
| 403 | insufficient_scope | Key lacks the read scope. |
| 429 | quota_exceeded | Over the portfolio.read SKU quota. |