API reference
API reference
Section titled “API reference”Series: v1 · version: 1.0.0
Preferred base: https://dayprotocol.com/api/v1
OpenAPI 3.1: dayprotocol.com/api/v1/openapi.json
Machine routes: GET /api/v1/day/routes
Error catalog: GET /api/v1/day/errors
Identity: wallet address only (DAY-294). No characters or accounts as first-class DAY concepts.
Under /api/v1, paths mirror the internal table:
/api/v1/day/status ≡ /api/day/status, /api/v1/wallets/{address}/position ≡ /api/wallets/{address}/position.
Legacy /api/v1/characters/{id}/… may still resolve as compat aliases — do not use in new clients.
X-API-Key: <key>| Role | Env | Endpoints |
|---|---|---|
| owner | DAY_OWNER_API_KEYS | route, withdraw, auto-pay, bridge rescue, PUT auto-yield, webhooks, cage policy |
| agent | DAY_AGENT_API_KEYS | GET position/portfolio/performance/funding/preview, GET auto-yield |
| keeper | DAY_KEEPER_API_KEYS | survival, harvest/batch, map/stats refresh |
| public / permissionless | — | status, venues, strategies, deposit plans, harvest poke, balances |
| HTTP | code | When |
|---|---|---|
| 401 | INVALID_API_KEY / UNAUTHORIZED | Key missing or not in allowlist |
| 403 | UNAUTHORIZED | Wrong role |
| 403 | WALLET_SCOPE | Wallet not allowed for this key |
X-Role is ignored. Do not send it for privilege.
import { DayClient } from "@dayprotocol/sdk";
const day = new DayClient({ baseUrl: "https://dayprotocol.com", // origin only — SDK never double-prefixes /api/v1 apiKey: process.env.DAY_OWNER_API_KEY,});Conventions
Section titled “Conventions”| Topic | Rule |
|---|---|
| identity | Wallet address only. Consumers map character/account → wallet outside DAY. |
| strategyId | Bare venue id: suilend, navi, kamino, jito, aave-v3, morpho-blue, … Not suilend-sui-usdc. |
| amounts | Integer micros strings ("1000000" = 1 USDC). |
| fees | Principal 0; harvest yield skim 500 bps; swap fee default 100 bps (disclosed). |
| plans | Prepare-only: ownerMustSign: true, submitted: false unless broadcast + real digest. |
| APY | Live or null — never fabricated. |
| status codes | 200 done · 202 prepared · 422 blocked · 401/403 auth · 429 rate limit |
Multi-chain honesty
Section titled “Multi-chain honesty”| Homes | Label |
|---|---|
| Sui, Solana | Executable (phase-1 route homes) |
| Base, Arbitrum | Map (discovery / prepare; broadcast off until GO + writeReady) |
GET /api/v1/day/status · public
Section titled “GET /api/v1/day/status · public”curl -sS https://dayprotocol.com/api/v1/day/statusGET /api/v1/openapi.json · public
Section titled “GET /api/v1/openapi.json · public”Codegen source. Alias: /openapi.json.
GET /api/v1/day/packages · public
Section titled “GET /api/v1/day/packages · public”Sui / Solana / Base / Arbitrum package ids + Map vs Executable labels.
GET /api/v1/day/errors · public
Section titled “GET /api/v1/day/errors · public”Versioned error + blocker enum. Renaming a code is breaking.
GET /api/v1/day/venues/apy · public
Section titled “GET /api/v1/day/venues/apy · public”Per-venue APY table; status: "unavailable" when live read fails.
Strategies & discovery
Section titled “Strategies & discovery”GET /api/v1/day/venues · public · listVenues()
Section titled “GET /api/v1/day/venues · public · listVenues()”curl -sS 'https://dayprotocol.com/api/v1/day/venues' | jq '.executionMode,.launchHomes,(.venues|length)'GET /api/v1/day/strategies · public · listStrategies()
Section titled “GET /api/v1/day/strategies · public · listStrategies()”curl -sS https://dayprotocol.com/api/v1/day/strategies | jq '.strategies[] | {strategyId,chain,ready}'GET /api/v1/day/strategies/{id} · public · getStrategy(id)
Section titled “GET /api/v1/day/strategies/{id} · public · getStrategy(id)”Bare id or form-* alias. Unknown → 404.
POST /api/v1/day/strategies/deposit/plan · public · prepareStrategyDeposit
Section titled “POST /api/v1/day/strategies/deposit/plan · public · prepareStrategyDeposit”curl -sS -X POST https://dayprotocol.com/api/v1/day/strategies/deposit/plan \ -H 'content-type: application/json' \ -d '{"strategyId":"suilend","amountMicros":"1000000"}'Principal fee 0. Same shape for every venue (venue-agnostic).
POST /api/v1/day/strategies/withdraw/plan · public · prepareStrategyWithdraw
Section titled “POST /api/v1/day/strategies/withdraw/plan · public · prepareStrategyWithdraw”Wallet money surface
Section titled “Wallet money surface”Canonical paths (no /day/ segment under wallets):
| Method | Path | Auth | SDK |
|---|---|---|---|
| GET | /api/v1/wallets/{address}/position | owner|agent | getPosition |
| GET | /api/v1/wallets/{address}/portfolio | owner|agent | getPortfolio |
| GET | /api/v1/wallets/{address}/performance | owner|agent | getPerformance |
| GET | /api/v1/wallets/{address}/funding | owner|agent | getFunding |
| POST | /api/v1/wallets/{address}/preview | owner|agent | previewRoute |
| POST | /api/v1/wallets/{address}/route | owner | routeYield |
| POST | /api/v1/wallets/{address}/harvest | permissionless | harvest |
| POST | /api/v1/wallets/{address}/withdraw | owner | withdraw |
| POST | /api/v1/wallets/{address}/auto-pay | owner | enableAutoPay |
| POST | /api/v1/wallets/{address}/rebalance | owner | — |
| GET/PUT | /api/v1/wallets/{address}/auto-yield | owner|agent / owner | getAutoYield / setAutoYield |
| POST | /api/v1/wallets/batch/positions | owner|agent | batchPositions |
export BASE=https://dayprotocol.com/api/v1export KEY=$DAY_OWNER_API_KEYexport W=0xYOUR_WALLET
curl -sS -H "X-API-Key: $KEY" "$BASE/wallets/$W/portfolio"curl -sS -H "X-API-Key: $KEY" "$BASE/wallets/$W/performance"curl -sS -X POST -H "X-API-Key: $KEY" -H 'content-type: application/json' \ -d "{\"amountMicros\":\"1000000\"}" "$BASE/wallets/$W/preview"Harvest notes
Section titled “Harvest notes”| Situation | HTTP | Body |
|---|---|---|
| No stake / no yield | 422 | mode: "no_op_harvest", outcome: "blocked" |
| Successful ledger harvest | 200 | gross / fee (500 bps) / net |
| Prepare-only edge | 202 | prepared: true |
Never invent gross yield from client body in production.
Chain balances (public)
Section titled “Chain balances (public)”| Path | Assets |
|---|---|
GET /api/v1/day/sui/wallet-balance?address= | Sui assets |
GET /api/v1/day/solana/wallet-balance?address= | SOL + USDC |
GET /api/v1/day/base/wallet-balance?address= | ETH + USDC |
GET /api/v1/day/arbitrum/wallet-balance?address= | ETH + USDC |
RPC failure → leg N/A (never invent).
Enablement: GET /api/v1/day/base/enablement, GET /api/v1/day/arbitrum/enablement.
Swaps (prepare-only)
Section titled “Swaps (prepare-only)”| Path | Chain |
|---|---|
POST /api/v1/day/jupiter/plan | Solana |
POST /api/v1/day/turbos/plan | Sui |
POST /api/v1/day/evm/swap/plan | Base / Arbitrum |
Fee line items + slippage bounds (default 100 bps, max 500). ownerMustSign: true. No custody.
Bridge (Mayan)
Section titled “Bridge (Mayan)”| Path | Auth |
|---|---|
POST /api/v1/day/bridge/plan | public |
POST /api/v1/day/bridge/delivery | owner|keeper |
POST /api/v1/day/bridge/rescue | owner |
Lifecycle: prepare → owner sign → delivery tracking → credit only after proof.
Rescue destination locked to owner. Fee/risk disclosure on every plan.
Autopilot is within-chain only — never silent cross-chain rebalance.
Webhooks
Section titled “Webhooks”| Path | Auth |
|---|---|
GET /api/v1/day/webhooks/events/types | public |
POST /api/v1/day/webhooks | owner (returns hmacKey once) |
GET /api/v1/day/webhooks | owner |
POST /api/v1/day/webhooks/{id}/rotate | owner |
DELETE /api/v1/day/webhooks/{id} | owner |
GET /api/v1/day/webhooks/events | owner|agent |
Events: deposit.settled, withdraw.settled, harvest.completed, bridge.delivered, bridge.failed, position.updated, apy.updated.
HMAC: sign `$\{timestamp\}.$\{rawBody\}` with hmacKey; header X-DAY-Signature: t=<unix>,v1=<hex>.
Cage (Base / Arbitrum)
Section titled “Cage (Base / Arbitrum)”Six actions: ROUTE · EXIT · REBALANCE · HARVEST · COMPOUND · AUTOPAY.
Owner signs; Day never holds keys; destination-lock on venues / payees / owner.
Base: /api/v1/day/base/cage, /api/v1/wallets/\{address\}/base/*
Arbitrum: /api/v1/day/arbitrum/cage, POST …/cage/prepare
Walkthrough
Section titled “Walkthrough”export BASE=https://dayprotocol.com/api/v1export KEY=$DAY_OWNER_API_KEYexport W=demo-wallet-1
# 1) discovercurl -sS "$BASE/day/strategies" | jq '.strategies[:3]'
# 2) deposit plan (prepare)curl -sS -X POST "$BASE/day/strategies/deposit/plan" \ -H 'content-type: application/json' \ -d '{"strategyId":"suilend","amountMicros":"1000000"}' | jq '{status,feeMicros,ownerMustSign}'
# 3) position / portfoliocurl -sS -H "X-API-Key: $KEY" "$BASE/wallets/$W/position"curl -sS -H "X-API-Key: $KEY" "$BASE/wallets/$W/portfolio"
# 4) harvest (permissionless poke)curl -sS -X POST -H 'content-type: application/json' \ -d '{}' "$BASE/wallets/$W/harvest" | jq '{httpStatus,mode,grossYieldMicros,protocolFeeMicros}'const day = new DayClient({ baseUrl: "https://dayprotocol.com", apiKey: process.env.DAY_OWNER_API_KEY });await day.listStrategies();await day.prepareStrategyDeposit({ strategyId: "suilend", amountMicros: "1000000" });await day.getPortfolio(process.env.DAY_WALLET_ADDRESS!);await day.getPerformance(process.env.DAY_WALLET_ADDRESS!);await day.harvest(process.env.DAY_WALLET_ADDRESS!, { execute: false });npm install github:dayprotocol/sdk# package name: @dayprotocol/sdk| Method | Route |
|---|---|
getPosition(wallet) | GET …/position |
getPortfolio(wallet) | GET …/portfolio |
getPerformance(wallet) | GET …/performance |
batchPositions(wallets) | POST …/batch/positions |
previewRoute / routeYield | POST …/preview · …/route |
harvest / withdraw | POST …/harvest · …/withdraw |
venueApyTable / errorCatalog | GET …/venues/apy · …/errors |
bridgePlan / bridgeRescuePlan | bridge/* |
baseWalletBalance / arbitrumWalletBalance | chain balances |
OpenAPI lockstep
Section titled “OpenAPI lockstep”When paths, auth, or examples change, update in the same change:
api/routes-manifest.mjsruntime/config/openapi.mjs- This page + day repo
docs/02-agent-api.md npm run check:docs-openapi
Live OpenAPI always wins for machines: openapi.json.