openapi: 3.1.0 info: title: Gauntlet Prices Users API description: Gauntlet vault data, user positions, and event analytics API. contact: name: Gauntlet url: https://gauntlet.xyz license: name: '' version: 1.0.0 tags: - name: Users paths: /v1/users/{wallet_address}/activity: get: tags: - Users summary: Get user wallet activity (deposits, withdrawals, transfers) description: "Immutable log of on-chain events that affected the wallet's vault position. Each row is a frozen-in-time record; rows never mutate after emission. \n\n`?vault_id=` narrows to one vault; omitted = activity across every vault the wallet has touched. Each row echoes its `vault_id` so wallet-wide consumers can distinguish per-vault activity. \n\nAsync deposit/redeem lifecycles emit multiple rows (one at request time with `status=pending`, a later one with `status=settled` or `refunded`). Consumers correlate them via `request_hash` to follow a single action across rows. Sync flows emit one row directly in the settled state. \n\nPagination is cursor-only. Default order is `desc` (newest first). Default page size 100, max 1000." operationId: get_user_activity parameters: - name: wallet_address in: path description: Ethereum wallet address required: true schema: type: string - name: vault_id in: query description: CAIP-10 vault identifier. Optional — omit for wallet-wide activity across every vault the wallet has touched. required: false schema: type: string - name: next in: query description: Opaque cursor from previous `meta.next_cursor`. required: false schema: type: string - name: limit in: query description: Page size (1–1000, default 100). required: false schema: type: integer format: int64 - name: order in: query description: 'Sort direction: `desc` (default) or `asc`.' required: false schema: type: string responses: '200': description: User wallet activity content: application/json: schema: $ref: '#/components/schemas/UserActivityResponse' '401': description: Missing or invalid auth content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '422': description: Invalid cursor content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /v1/users/{wallet_address}/positions: get: tags: - Users summary: Get all current positions for a wallet description: 'Returns every vault position the wallet currently holds or has pending exposure in (pending deposit or redeem). Fully-exited positions (zero shares, no pending escrow) are excluded. All monetary metrics include a `usd` field (null when pricing is unavailable). `value.usd` and `pending_deposit_assets.usd` use the current spot price. `cost_basis.usd` and `pnl.realized.usd` are computed by replaying on-chain events against the token''s historical price series — the same method used by `GET /v1/users/{wallet}/positions/{vault_id}`. `pnl.unrealized.usd`, `pnl.total.usd`, and `roi_pct.usd` are derived from those. Cursor-paginated on internal position ID. Default page size 100, max 500.' operationId: get_user_all_positions parameters: - name: wallet_address in: path description: Ethereum wallet address required: true schema: type: string - name: next in: query description: Opaque cursor from previous `meta.next_cursor`. required: false schema: type: string - name: limit in: query description: Page size (1–500, default 100). required: false schema: type: integer format: int64 responses: '200': description: All wallet positions content: application/json: schema: $ref: '#/components/schemas/UserAllPositionsResponse' '401': description: Missing or invalid auth content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '422': description: Invalid cursor content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /v1/users/{wallet_address}/positions/{vault_id}: get: tags: - Users summary: Get user position in a specific vault description: Returns the current position snapshot for a wallet in a single vault. Historical points live on `/positions/{vault_id}/timeseries`. operationId: get_user_vault_position parameters: - name: wallet_address in: path description: Ethereum wallet address required: true schema: type: string - name: vault_id in: path description: Vault identifier required: true schema: type: string responses: '200': description: Single vault position content: application/json: schema: $ref: '#/components/schemas/UserPositionLatestResponse' '401': description: Missing or invalid auth content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '404': description: Position not found content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' /v1/users/{wallet_address}/positions/{vault_id}/timeseries: get: tags: - Users summary: Get user position timeseries for a specific vault description: Returns historical value, cost basis, grouped PnL, and ROI data for a single vault position. Default order is `asc` (oldest first, chart-friendly); pass `?order=desc` for newest-first list views. Cursor-paginated — pass `meta.next_cursor` back as `?next=` for the next page (cursor is bound to the order it was created with). Defaults to `granularity=day` (one UTC-midnight snapshot per day); `week` returns Monday 00:00 UTC snapshots, `month` returns first-of-month 00:00 UTC snapshots, and `hour` returns the raw hourly cadence. Default page size is 1000. operationId: get_user_vault_position_timeseries parameters: - name: wallet_address in: path description: Ethereum wallet address required: true schema: type: string - name: vault_id in: path description: Vault identifier required: true schema: type: string - name: start in: query description: 'Window start: ISO 8601 date (`2026-01-01`, read as 00:00:00 UTC) or RFC 3339 timestamp (`2026-01-01T00:00:00Z`).' required: false schema: type: string - name: end in: query description: 'Window end: ISO 8601 date (`2026-01-01`, read as 00:00:00 UTC) or RFC 3339 timestamp (`2026-01-01T00:00:00Z`).' required: false schema: type: string - name: next in: query description: Opaque cursor from previous `meta.next_cursor`. required: false schema: type: string - name: limit in: query description: Page size (1–10000, default 1000). required: false schema: type: integer format: int64 - name: order in: query description: 'Sort direction: `asc` (default) or `desc`.' required: false schema: type: string - name: granularity in: query description: 'Sampling granularity: `day` (default), `hour`, `week`, or `month`. Day/week/month buckets start at 00:00 UTC; weeks start Monday and months start on the 1st.' required: false schema: type: string responses: '200': description: Position timeseries content: application/json: schema: $ref: '#/components/schemas/UserPositionsTimeseriesResponse' '401': description: Missing or invalid auth content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '422': description: Invalid cursor content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' components: schemas: UserPositionsTimeseriesResponse: type: object required: - meta - data properties: data: type: array items: $ref: '#/components/schemas/PositionTimeseriesPoint' meta: $ref: '#/components/schemas/TimeseriesMeta' UserActivity: type: object description: 'One immutable entry in the wallet''s activity log. Each row represents a single on-chain event that affected the wallet''s vault position. Async deposit/redeem lifecycles emit multiple rows (one per lifecycle event — request, solve, refund); each row is frozen at emission time and never mutates. To follow an async action across rows, correlate via `request_hash`.' required: - block_timestamp - type - vault_id - tx_hash - block_number - block_hash - shares_delta - assets_delta properties: assets_delta: $ref: '#/components/schemas/AssetDelta' description: "Signed asset delta in the row's asset-token units, using a\ndeposit-ledger sign convention (NOT wallet-flow direction):\n- Positive = a deposit-direction action (`deposit`,\n `deposit_pending`, `transfer_in`).\n- Negative = a withdraw-direction action (`withdraw`,\n `deposit_refunded`, `transfer_out`).\n- `0` = no asset movement at this event\n (`deposit` on Aera async solve, `withdraw_pending`,\n `withdraw_refunded`).\n\nNote: under this convention `deposit_refunded` is negative\n(a deposit was unwound) even though tokens flow back INTO the\nwallet, and async `withdraw` (Aera redeem_solved) is negative\neven though tokens flow back INTO the wallet — the sign tracks\nthe deposit-ledger direction, not the user's wallet balance.\n\nSumming across rows for a single async lifecycle gives the net\nsigned asset movement of that lifecycle (no double-counting).\n`assets_delta.token` identifies the asset token when known. Emitted\nas a struct (`{ native: \"...\", token: { address, symbol } }`) so\nderived denominations (e.g. usd) can be added later without breaking\nthe response shape." block_hash: type: string description: 'Block hash — 1:1 identifier for the block this event was mined in. Consumers needing to detect reorgs should key off this rather than `block_number` (multiple blocks can share a number across a reorg).' block_number: type: integer format: int64 description: 'Block number — kept alongside `block_timestamp` for on-chain reconciliation / explorer linking.' block_timestamp: type: integer format: int64 description: Unix seconds, block time (`block.timestamp` from the chain). request_hash: type: - string - 'null' description: 'Aera async-flow correlation hash. Links a `*_pending` row to its later terminal row (bare `deposit`/`withdraw` for settled, or `*_refunded`) of the same lifecycle. Emitted only on rows that participate in an async flow; omitted on sync rows and on secondary-market transfers.' shares_delta: type: string description: "Signed share delta in 18-decimal units, reported at the event\nwhere the shares actually moved. Conventions by row type:\n- `deposit` — positive (shares minted to the wallet).\n- `deposit_pending` / `deposit_refunded` — `0` (no share\n movement; deposit requests touch assets only).\n- `withdraw_pending` — negative for Aera async redeems (shares\n leave the wallet at request time, escrowed to the Provisioner).\n- `withdraw` — negative for sync (Morpho) withdraws (shares\n burn on the same row that pays out assets); `0` for Aera\n async redeems (the share movement is recorded on the paired\n `withdraw_pending` row).\n- `withdraw_refunded` — positive (escrowed shares return).\n- `transfer_in` — positive; `transfer_out` — negative.\n\nSumming across rows for a single async lifecycle gives the net\nshare movement of that lifecycle — there is no double-counting." tx_hash: type: string description: Transaction hash of the on-chain event. type: type: string description: 'What happened. One of: - `deposit` — settled deposit (sync vault flow or async terminal solve). - `deposit_pending` — async deposit request submitted; awaiting solver. - `deposit_refunded` — async deposit returned without settling; assets bounced back. - `withdraw` — settled withdrawal (sync vault flow or async terminal solve). - `withdraw_pending` — async redeem request submitted; awaiting solver. - `withdraw_refunded` — async redeem returned without settling; shares bounced back. - `transfer_in` — vault shares received from another EOA (secondary market). - `transfer_out` — vault shares sent to another EOA. Async deposit/redeem lifecycles emit two rows (a `*_pending` at request time, then a separate terminal row — bare `deposit` or `_refunded` — at solve time). Rows are immutable; the pending row never mutates. Correlate the pair via `request_hash`.' vault_id: type: string description: CAIP-10 vault identifier this row belongs to. Always emitted. UserActivityResponse: type: object required: - meta - data properties: data: type: array items: $ref: '#/components/schemas/UserActivity' meta: $ref: '#/components/schemas/TimeseriesMeta' BasicMeta: type: object required: - request_id - refreshed_at properties: refreshed_at: type: string format: date-time request_id: type: string UserPositionMetrics: type: object required: - pending_deposit_assets - shares_owned - pending_redeem_shares - value - cost_basis - pnl - roi_pct properties: cost_basis: $ref: '#/components/schemas/AmountPair' description: Cumulative cost of currently-held shares. pending_deposit_assets: $ref: '#/components/schemas/AmountPair' description: 'Assets escrowed at the Aera Provisioner pending share mint (`native` = numeraire-token units, `usd` = `native` × current USD price).' pending_redeem_shares: type: string description: Shares escrowed at the Aera Provisioner pending asset return. pnl: $ref: '#/components/schemas/PnlBreakdown' description: Profit and loss grouped by total, unrealized, and realized values. roi_pct: $ref: '#/components/schemas/RatioPair' description: Time-weighted ROI from user deposit/redeem history. shares_owned: type: string description: Shares currently held by the wallet. value: $ref: '#/components/schemas/AmountPair' description: 'Current market value of held shares (`native` = numeraire-token units, `usd` = `native` × current USD price).' PnlBreakdown: type: object required: - total - unrealized - realized properties: realized: $ref: '#/components/schemas/AmountPair' description: Locked-in PnL from past disposals. total: $ref: '#/components/schemas/AmountPair' description: '`unrealized` + `realized`.' unrealized: $ref: '#/components/schemas/AmountPair' description: '`value` − `cost_basis`.' PartialResponseError: type: object required: - code - message properties: code: type: string description: Machine-readable error code for the isolated item failure. message: type: string description: Human-readable error message. resource_id: type: - string - 'null' description: Resource that failed inside the aggregate response, when known. ErrorResponse: type: object description: Standard error response envelope returned on 4xx/5xx required: - error properties: error: $ref: '#/components/schemas/ErrorBody' PositionTimeseriesPoint: type: object required: - timestamp - shares_owned - value - cost_basis - pnl - roi_pct properties: cost_basis: $ref: '#/components/schemas/AmountPair' description: Cumulative cost of held shares (`usd` uses per-event historical pricing). pnl: $ref: '#/components/schemas/PnlBreakdown' description: Profit and loss grouped by total, unrealized, and realized values. roi_pct: $ref: '#/components/schemas/RatioPair' description: ROI ratio (`native` is in-kind; `usd` is null when pricing unavailable). shares_owned: type: string description: Shares currently held by the wallet at this timestamp. timestamp: type: string format: date-time value: $ref: '#/components/schemas/AmountPair' description: 'Position value at this timestamp (`native` = numeraire-token units, `usd` = `native` × historical USD price; null when unavailable).' UserPosition: type: object required: - vault_id - wallet_address - metrics properties: metrics: $ref: '#/components/schemas/UserPositionMetrics' numeraire_token: oneOf: - type: 'null' - $ref: '#/components/schemas/TokenRef' vault_id: type: string wallet_address: type: string AssetDelta: type: object description: 'Asset-delta envelope on user activity rows. `native` is always present; `token` is present when the indexer knows the row''s asset token. The struct shape is kept stable so derived denominations (usd, numeraire token) can be added later without breaking integrators.' required: - native properties: native: type: string token: oneOf: - type: 'null' - $ref: '#/components/schemas/TokenRef' RatioPair: type: object description: 'JSON-number ratio paired across native (in-kind) and USD denominations. Null when event history is unavailable or cannot support ROI replay.' properties: native: type: - number - 'null' format: double usd: type: - number - 'null' format: double AmountPair: type: object description: 'Decimal-string metric paired across native (numeraire-token) and USD. `native` is always present; `usd` is JSON null when pricing is unavailable.' required: - native properties: native: type: string usd: type: - string - 'null' UserAllPositionsResponse: type: object required: - meta - data properties: data: type: array items: $ref: '#/components/schemas/UserPosition' meta: $ref: '#/components/schemas/TimeseriesMeta' ErrorBody: type: object required: - code - message properties: code: type: string description: Machine-readable error code (e.g. `NOT_FOUND`, `UNAUTHORIZED`) details: {} message: type: string description: Human-readable error message UserPositionLatestResponse: type: object required: - meta - data properties: data: $ref: '#/components/schemas/UserPosition' meta: $ref: '#/components/schemas/BasicMeta' TokenRef: type: object required: - address properties: address: type: string decimals: type: - integer - 'null' format: int32 symbol: type: - string - 'null' TimeseriesMeta: type: object required: - request_id - refreshed_at - count - limit properties: count: type: integer format: int64 description: Number of points in this response. end: type: - string - 'null' format: date-time limit: type: integer format: int64 description: Page-size cap actually applied. next_cursor: type: - string - 'null' description: Set when more pages exist; pass back as `?next=`. partial_errors: type: - array - 'null' items: $ref: '#/components/schemas/PartialResponseError' description: Item-scoped failures isolated from an aggregate response. refreshed_at: type: string format: date-time request_id: type: string start: type: - string - 'null' format: date-time description: Window bounds the response covers (echoes the request when set).