Developer-facing reference for the VaultQuest backend REST API. Covers pool actions, dashboard summary, saved-pools watchlist, and activity export. Frontend contributors can build UI integrations against these shapes without reading the backend source.
All responses use application/json unless noted. Successful responses wrap
data in { "data": ... }. Paginated responses include a meta.pagination
block. Errors return { "error": { "code": "...", "message": "..." } }.
There is no session-based auth. Wallet-scoped endpoints accept the connected wallet address as a query parameter. The frontend is responsible for passing the user's own address — the API trusts this parameter.
Create a new wallet action intent.
Headers
| Header | Required | Description |
|---|---|---|
Idempotency-Key |
Yes | UUID v4. Reusing the same key with the same payload is a safe no-op (returns 200). Reusing with a different payload returns 409. |
Request body
{
"wallet_address": "GABCDEF1234567890",
"action_type": "deposit",
"action_payload": {
"vault_id": "42",
"amount": "1000000",
"token": "USDC"
}
}| Field | Type | Values |
|---|---|---|
wallet_address |
string | Stellar wallet address (max 120 chars) |
action_type |
enum | deposit withdraw create_vault claim select_winner |
action_payload |
object | Arbitrary JSON; shape depends on action_type |
Response — 201 Created (new action) or 200 OK (idempotent replay)
{
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"idempotency_key": "a4e8b0c2-...",
"wallet_address": "GABCDEF1234567890",
"action_type": "deposit",
"action_payload": { "vault_id": "42", "amount": "1000000", "token": "USDC" },
"status": "pending",
"tx_hash": null,
"soroban_event_id": null,
"correlation_id": "...",
"error_code": null,
"error_detail": null,
"retry_count": 0,
"created_at": "2025-05-29T12:00:00.000Z",
"updated_at": "2025-05-29T12:00:00.000Z",
"submitted_at": null,
"confirmed_at": null,
"redacted_at": null
}
}List actions for a wallet, newest first.
Query parameters
| Param | Required | Default | Description |
|---|---|---|---|
wallet |
Yes | — | Wallet address |
status |
No | — | Filter: pending submitted confirmed failed reverted orphaned |
cursor |
No | — | UUID of the last item from the previous page |
limit |
No | 25 | Items per page (1–100) |
Response — 200 OK
{
"data": [ /* array of action objects */ ],
"meta": {
"pagination": {
"next_cursor": "550e8400-...",
"limit": 25,
"has_more": true
}
}
}Get a single action by ID.
Response — 200 OK — action object (same shape as POST response)
Response — 404 Not Found
{ "error": { "code": "NOT_FOUND", "message": "action <id> not found" } }Attach a transaction hash after the wallet has broadcast to the network.
Advances status from pending → submitted.
Request body
{ "tx_hash": "abc123..." }Response — 200 OK — updated action object
Cancel a pending action (e.g. user rejected the wallet prompt).
Advances status from pending → failed.
Request body
{
"error_code": "WALLET_REJECTED",
"error_detail": "User dismissed the wallet popup"
}error_code values |
Meaning |
|---|---|
WALLET_REJECTED |
User explicitly rejected the signing request |
WALLET_TIMEOUT |
Signing timed out with no response |
NETWORK_ERROR |
Could not reach the RPC endpoint |
Response — 200 OK — updated action object
Scrub all personal data for a wallet (GDPR / right-to-erasure). Sets
action_payload to null and stamps redacted_at on all rows.
Scrubbed rows are excluded from future export responses.
Response — 200 OK
{ "data": { "scrubbed": 12 } }Export the wallet's full activity history as JSON or CSV.
Authorization (required)
Activity export discloses transaction history, so wallet selects the data but
does not authorize it. Every request must present one of the following
principals, or the endpoint answers 401 UNAUTHORIZED. There is no anonymous
access, and unlike the /api/* API-key guard this is never disabled by missing
configuration.
Wallet owner — signed challenge. Prove control of the address's key by signing a challenge. Authorized for that wallet only; a wallet may export only its own history.
| Header | Value |
|---|---|
X-Wallet-Address |
The G... address being exported |
X-Wallet-Timestamp |
Current time in Unix milliseconds |
X-Wallet-Signature |
Base64 ed25519 signature over the challenge string |
The challenge string is:
vaultquest:actions-export:<wallet-address>:<timestamp-ms>
The timestamp must be within EXPORT_SIGNATURE_TTL_MS (default 5 minutes) of
server time, in either direction, which bounds how long a captured signature
stays usable. If the wallet query parameter names a different address than
X-Wallet-Address, the request is rejected with 403 FORBIDDEN.
Service — shared credential. Internal and third-party consumers may export any wallet. Present exactly one of:
| Header | Value |
|---|---|
X-Internal-Secret |
INTERNAL_SERVICE_SECRET (always configured) |
X-Api-Key |
API_KEY (only when configured) |
Existing internal consumers that already send X-Internal-Secret keep working
with no change. Browser callers must migrate to the signed-challenge headers;
the frontend exportActivity client accepts an authHeaders argument for this.
Query parameters
| Param | Required | Default | Description |
|---|---|---|---|
wallet |
Yes | — | Wallet address |
format |
No | json |
json or csv |
from |
No | — | ISO 8601 datetime — return actions created at or after this time |
to |
No | — | ISO 8601 datetime — return actions created at or before this time |
limit |
No | 500 | Max rows returned (1–1000) |
Response — 200 OK (JSON format)
{
"data": [
{
"id": "550e8400-...",
"wallet_address": "GABCDEF1234567890",
"action_type": "deposit",
"action_payload": { "vault_id": "42", "amount": "1000000", "token": "USDC" },
"status": "confirmed",
"tx_hash": "abc123...",
"error_code": null,
"created_at": "2025-05-29T12:00:00.000Z",
"submitted_at": "2025-05-29T12:00:05.000Z",
"confirmed_at": "2025-05-29T12:00:30.000Z"
}
]
}Response — 200 OK (CSV format)
Returns Content-Type: text/csv with Content-Disposition: attachment; filename="vaultquest-activity-<wallet-prefix>.csv".
"id","date","action_type","pool_id","amount","token","status","tx_hash","error_code","submitted_at","confirmed_at"
"550e8400-...","2025-05-29T12:00:00.000Z","deposit","42","1000000","USDC","confirmed","abc123...","","2025-05-29T12:00:05.000Z","2025-05-29T12:00:30.000Z"
Notes
- Scrubbed rows (
redacted_at != null) are never included in export output. - Large histories: use
from/todate ranges to paginate manually. Thelimitcap is 1 000 rows per request. - Wallet-scoping: the export only returns data for the
walletparameter value, and a wallet-owner principal may only name its own address. Never returns another user's data. - Errors follow the standard envelope:
401 UNAUTHORIZEDwhen no valid principal is presented,403 FORBIDDENwhen an authenticated wallet names a different wallet.
Aggregated dashboard rollup for a wallet. Provides per-status action counts, in-flight tx hashes the wallet should keep polling, and a freshness flag.
Query parameters
| Param | Required | Default | Description |
|---|---|---|---|
wallet |
Yes | — | Wallet address |
stale_after_ms |
No | 300 000 (5 min) | If the most recent ledger update is older than this, is_stale is true |
Response — 200 OK
{
"data": {
"wallet_address": "GABCDEF1234567890",
"total_actions": 14,
"by_status": {
"pending": 0,
"submitted": 1,
"confirmed": 11,
"failed": 1,
"reverted": 1,
"orphaned": 0
},
"pending_tx_hashes": ["abc123..."],
"is_stale": false,
"latest_activity_at": "2025-05-29T12:00:00.000Z",
"latest_confirmed_at": "2025-05-29T11:55:00.000Z"
}
}Return the saved pools for a wallet, newest first.
Query parameters
| Param | Required | Default | Description |
|---|---|---|---|
wallet |
Yes | — | Wallet address |
Response — 200 OK
{
"data": [
{
"id": "550e8400-...",
"wallet_address": "GABCDEF1234567890",
"pool_id": "pool-42",
"pool_name": "Weekly USDC",
"status": "open",
"tvl": "12500.5",
"asset": "USDC",
"participant_count": 24,
"expected_yield": "5.2% APY",
"prize": "50 USDC",
"opens_at": "2026-05-29T12:00:00.000Z",
"locks_at": "2026-06-05T12:00:00.000Z",
"draws_at": "2026-06-12T12:00:00.000Z",
"created_at": "2026-05-29T12:00:00.000Z",
"updated_at": "2026-05-29T12:00:00.000Z"
}
]
}Create or update a saved pool entry for a wallet. Reusing the same wallet and pool ID updates the stored summary instead of creating duplicates.
Request body
{
"wallet_address": "GABCDEF1234567890",
"pool": {
"pool_id": "pool-42",
"pool_name": "Weekly USDC",
"status": "open",
"tvl": "12500.5",
"asset": "USDC",
"participant_count": 24,
"expected_yield": "5.2% APY",
"prize": "50 USDC",
"opens_at": "2026-05-29T12:00:00.000Z",
"locks_at": "2026-06-05T12:00:00.000Z",
"draws_at": "2026-06-12T12:00:00.000Z"
}
}Response — 201 Created for a new saved pool, or 200 OK when updating an existing entry
{
"data": {
"saved": {
"id": "550e8400-...",
"wallet_address": "GABCDEF1234567890",
"pool_id": "pool-42",
"pool_name": "Weekly USDC",
"status": "open",
"tvl": "12500.5",
"asset": "USDC",
"participant_count": 24,
"expected_yield": "5.2% APY",
"prize": "50 USDC",
"opens_at": "2026-05-29T12:00:00.000Z",
"locks_at": "2026-06-05T12:00:00.000Z",
"draws_at": "2026-06-12T12:00:00.000Z",
"created_at": "2026-05-29T12:00:00.000Z",
"updated_at": "2026-05-29T12:00:00.000Z"
}
}
}Remove a saved pool entry for the wallet supplied in the query string.
Query parameters
| Param | Required | Default | Description |
|---|---|---|---|
wallet |
Yes | — | Wallet address |
Response — 200 OK
{ "data": { "deleted": 1 } }| Code | HTTP | Meaning |
|---|---|---|
NOT_FOUND |
404 | Resource does not exist |
INVALID_PAYLOAD |
400 | Request body or query params failed validation |
ILLEGAL_TRANSITION |
409 | Status transition is not allowed (e.g. cancel a confirmed action) |
IDEMPOTENCY_KEY_REUSED_WITH_DIFFERENT_PAYLOAD |
409 | Same Idempotency-Key used with a different body |
TX_HASH_ALREADY_ATTACHED |
409 | tx_hash is already owned by another action |
UNAUTHORIZED |
401 | Request lacks required credentials (internal endpoints) |
pending ──► submitted ──► confirmed
│ └──────► reverted
└──────────────────────► failed
submitted ────────────────► orphaned
Terminal states (no further transitions): confirmed, failed, reverted, orphaned.
action_type |
Payload fields |
|---|---|
deposit |
vault_id, amount, token |
withdraw |
vault_id, amount, token |
create_vault |
vault_id, amount, token |
claim |
vault_id |
select_winner |
vault_id |
The action_payload is stored verbatim and surfaced as-is in responses and
exports. Consumers should treat unknown fields as additive and not error on them.