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).