This project exposes APIs in two layers:
- Soroban smart contract API (
contracts/vault) - Frontend TypeScript API (
frontend/src)
The backend API provides RESTful endpoints for the YieldVault application.
http://localhost:3000
The backend supports two authentication schemes:
Authorization: Bearer <access-token>— user session authentication for wallet-based access.Authorization: ApiKey <api-key>— admin/system authentication for privileged backend operations.
Note: backend auth-protected routes require the
Authorizationheader. Thex-api-keyheader is used only as a rate-limiting fallback key and is not accepted as the authentication credential for admin routes.
Admin routes and privileged backend operations use API keys.
- Header format:
Authorization: ApiKey <api-key> - Applies to all
/admin/*endpoints. - Also applies to admin transaction exports on
GET /api/v1/vault/transactions/export.
API key roles:
admin- Allowed to access protected admin endpoints.
- Allowed to perform admin-scoped transaction exports.
super-admin- Has all
adminprivileges. - Required for super-admin-only actions:
GET /admin/impersonate/:walletDELETE /admin/idempotency/keysPOST /admin/api-keys/registerwhen creating a key with rolesuper-admin
- Has all
When registering a new API key via POST /admin/api-keys/register, an existing admin key can create another admin key, but only an existing super-admin key may register a new super-admin key.
User session authentication uses JWT access tokens and refresh tokens.
POST /api/v1/auth/login- Body:
{ "walletAddress": "<wallet-address>" } - Returns a Bearer access token and a refresh token.
- Body:
POST /api/v1/auth/refresh- Body:
{ "refreshToken": "<refresh-token>" } - Rotates the refresh token and returns a new access token pair.
- Body:
POST /api/v1/auth/logout- Requires
Authorization: Bearer <access-token>. - Revokes the current session.
- Requires
POST /api/v1/auth/logout-all- Requires
Authorization: Bearer <access-token>. - Revokes all active sessions for the authenticated wallet.
- Requires
GET /api/v1/vault/transactions/export supports both authentication methods:
Authorization: Bearer <access-token>- The request is scoped to the wallet in the token subject.
- If
walletAddressis provided, it must match the authenticated wallet. - Attempting to export another wallet's transactions returns
403 Forbidden.
Authorization: ApiKey <api-key>- Requires an
admin-role API key. walletAddressis required for admin exports.- Allows exporting any wallet's transactions when authorized.
- Requires an
GET /health- Service health statusGET /ready- Readiness status
GET /api/vault/summary- Get vault summaryGET /api/vault/history- Get vault history with pagination
GET /api/transactions- List transactions with pagination and filtering
GET /api/portfolio/holdings- List portfolio holdings with pagination and filtering
All list endpoints support standardized pagination. See PAGINATION.md for detailed documentation, including deterministic paging walkthroughs and cursor usage examples.
Quick Example:
# Get first 20 transactions
curl "http://localhost:3000/api/transactions?limit=20"
# Get next page using cursor
curl "http://localhost:3000/api/transactions?limit=20&cursor=base64encodedcursor"Complete examples:
The API uses URL path versioning (/api/v1/). All new integrations must target the
versioned base path. Unversioned legacy paths redirect with 301 and will be removed
after the transition window.
See VERSIONING.md for the complete versioning scheme, deprecation windows, sunset policy, and client migration guide.
API endpoints are rate limited. See RATE_LIMITING.md for details.
All errors follow a consistent format:
{
"error": "Error Type",
"status": 400,
"message": "Human-readable error message"
}| Document | Purpose |
|---|---|
| ERROR_FORMAT.md | Frontend ApiError / ValidationError shapes and handling patterns |
| ERROR_CODE_CATALOG.md | Full error code list, HTTP/Soroban codes, and integrator remediation |
See ERROR_CODE_CATALOG.md when building SDKs or support runbooks; use ERROR_FORMAT.md when working in the React client.
cargo doc -p vault --no-depscd frontend
npm install
npm run docs:apiGenerated output:
- Rust docs:
target/doc - Frontend docs:
docs/api/frontend
GET /api/transactionsQuery Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
limit |
number | 20 | Number of items per page (1-100) |
cursor |
string | - | Cursor for next page |
page |
number | - | Page number (1-based) |
sortBy |
string | timestamp | Field to sort by |
sortOrder |
string | desc | Sort direction (asc/desc) |
type |
string | all | Filter by type (deposit/withdrawal/all) |
walletAddress |
string | - | Filter by wallet address |
Response:
{
"data": [
{
"id": "tx-1",
"type": "deposit",
"amount": "100.00",
"asset": "USDC",
"timestamp": "2026-03-28T18:00:00.000Z",
"transactionHash": "hash-1-abc123",
"walletAddress": "GABC..."
}
],
"pagination": {
"count": 20,
"total": 100,
"nextCursor": "base64encodedcursor",
"hasNextPage": true,
"hasPrevPage": false
},
"timestamp": "2026-03-28T18:00:00.000Z"
}GET /api/portfolio/holdingsQuery Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
limit |
number | 20 | Number of items per page (1-100) |
cursor |
string | - | Cursor for next page |
page |
number | - | Page number (1-based) |
sortBy |
string | valueUsd | Field to sort by |
sortOrder |
string | desc | Sort direction (asc/desc) |
status |
string | all | Filter by status (active/pending/all) |
walletAddress |
string | - | Filter by wallet address |
Response:
{
"data": [
{
"id": "holding-1",
"asset": "USDC",
"vaultName": "Vault 1",
"symbol": "USDC",
"shares": 100,
"apy": 5.5,
"valueUsd": 100.00,
"unrealizedGainUsd": 5.00,
"issuer": "YieldVault",
"status": "active",
"walletAddress": "GABC..."
}
],
"pagination": {
"count": 20,
"total": 50,
"nextCursor": "base64encodedcursor",
"hasNextPage": true,
"hasPrevPage": false
},
"timestamp": "2026-03-28T18:00:00.000Z"
}GET /api/vault/historyQuery Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
limit |
number | 30 | Number of items per page (1-365) |
cursor |
string | - | Cursor for next page |
page |
number | - | Page number (1-based) |
sortBy |
string | date | Field to sort by |
sortOrder |
string | desc | Sort direction (asc/desc) |
from |
string | - | Start date (YYYY-MM-DD) |
to |
string | - | End date (YYYY-MM-DD) |
Response:
{
"data": [
{
"date": "2026-03-28",
"value": 103.75
}
],
"pagination": {
"count": 30,
"total": 365,
"nextCursor": "base64encodedcursor",
"hasNextPage": true,
"hasPrevPage": false
},
"timestamp": "2026-03-28T18:00:00.000Z"
}- Added API versioning and deprecation policy (VERSIONING.md)
- Initial API documentation
- Pagination conventions
- Rate limiting documentation
- Error format documentation