On this page
Portfolio
GET /v1/portfolio aggregates wallet positions across every provider Artery
supports for on-chain identities. One call fans out — currently Polymarket
- Hyperliquid — and returns a unified envelope with both the raw upstream
payload (
native) and a normalizedvalueUsdper slice.
When to use this
- Account dashboards — show "total USDC across all venues" for a wallet without writing per-venue glue code.
- PnL reconciliation — pair with
/v1/me/pnlto compare realized vs current value. - Risk monitoring — sum exposure across Polymarket bets and HL perps for a watched address.
For per-wallet trade history (fills, fees, etc.) use
/v1/me/fills — it shares the same wallet identity model.
Request
bashcurl -H "Authorization: Bearer art_live_<your-key>" \
"https://api.artery.questflow.ai/v1/portfolio?user=0x9d84cbc7eb19c4cbb24f3866c70a5fcab502d1dc&provider=polymarket,hyperliquid"Query parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
user | string | yes | EVM address, 0x + 40 hex chars. Lowercased server-side before forwarding. |
provider | string | no | Comma-separated subset of polymarket, hyperliquid. Omit to fan out to every supported provider. |
Unknown provider names return 400 unknown_provider with the offending
values listed. The full set lives in the providers field of every
response so you can discover-then-filter.
Response
jsonc{
"user": "0x9d84cbc7eb19c4cbb24f3866c70a5fcab502d1dc",
"providers": ["polymarket", "hyperliquid"],
"slices": [
{
"provider": "polymarket",
"native": [
// Verbatim Polymarket position array — one row per market the
// wallet has any size on. Keys match Polymarket's own API.
],
"valueUsd": 1234.56,
"note": null
},
{
"provider": "hyperliquid",
"native": {
// Verbatim HL `clearinghouseState` — assetPositions[], marginSummary,
// crossMarginSummary, withdrawable, time. See HL docs for the full shape.
},
"valueUsd": 5678.90,
"note": null
}
],
"summary": {
"totalValueUsd": 6913.46,
"providersReporting": 2
},
"warnings": [],
"fetchedAt": "2026-05-19T07:00:00.000Z"
}Aggregation semantics
slices[i].nativeis the untransformed upstream payload. Polymarket returns an array (one row per position); Hyperliquid returns an object (the fullclearinghouseStateenvelope includingassetPositions[],marginSummary,crossMarginSummary,withdrawable, andtime). Consumers that want raw venue data don't have to make two more calls.slices[i].valueUsdis the USDC-denominated wallet value when the provider exposes one, elsenull. Polymarket returns position notionals; HL returns account equity frommarginSummary.accountValue. Implementations evolve — treat this field as best-effort and fall back tonativefor audit-grade work.summary.totalValueUsdsums slices that returned a number. Slices withvalueUsd: nullare excluded from the sum but still counted inslices.providersReportingis the count of slices that contributed.warnings[]carries soft failures — provider 404, upstream timeout, partial parse — so one bad provider doesn't 5xx the whole response. When a provider call fails entirely you'll see a warning ANDslices[i].notedescribing the failure, withvalueUsd: null.fetchedAtis when the server completed the fan-out. Both legs are fetched in parallel viaPromise.allSettled; the slower one bounds the total response time.
Error responses
| HTTP | error.code | When |
|---|---|---|
| 400 | validation_failed | user missing or not a 0x-40-hex address. |
| 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 | rate_limited | Over the portfolio.read SKU quota — see headers x-quota-portfolio-*. |
Worked example
bash# A wallet active on both Polymarket + HL perps
curl -H "Authorization: Bearer art_live_<your-key>" \
"https://api.artery.questflow.ai/v1/portfolio?user=0xabc...&provider=polymarket,hyperliquid"jsonc{
"user": "0xabc...",
"providers": ["polymarket", "hyperliquid"],
"slices": [
{
"provider": "polymarket",
"native": [
{
"conditionId": "0xCONDITION_ID",
"outcome": "YES",
"size": "150.00",
"avgPrice": "0.62",
"currentValue": "93.00"
}
],
"valueUsd": 93.0,
"note": null
},
{
"provider": "hyperliquid",
"native": {
"assetPositions": [
{ "type": "oneWay", "position": { "coin": "BTC", "szi": "0.5", "entryPx": "65000", "positionValue": "33850.5" } }
],
"marginSummary": { "accountValue": "12450.78", "totalNtlPos": "33850.5" },
"withdrawable": "8400.21",
"time": 1779163200000
},
"valueUsd": 12450.78,
"note": null
}
],
"summary": {
"totalValueUsd": 12543.78,
"providersReporting": 2
},
"warnings": [],
"fetchedAt": "2026-05-19T07:00:00.000Z"
}When the same wallet has no Polymarket activity:
jsonc{
"user": "0xabc...",
"providers": ["polymarket", "hyperliquid"],
"slices": [
{ "provider": "polymarket", "native": [], "valueUsd": null, "note": null },
{ "provider": "hyperliquid", "native": { ... }, "valueUsd": 12450.78, "note": null }
],
"summary": { "totalValueUsd": 12450.78, "providersReporting": 1 },
"warnings": [],
"fetchedAt": "2026-05-19T07:00:00.000Z"
}valueUsd: null + empty native[] is the canonical "no positions" shape —
not an error. summary ignores the null and the total still makes sense.
Quota
This endpoint is metered under the portfolio.read SKU. Each successful
response counts as 1 unit. Per-tier daily caps live in the
rate limits page.