USDC yield API reference
HTTP API to drive Earn strategies end to end. Version 1.13.0.
Base URL
https://earn-api.quicknode.dev/functions/v1/apiProduction
The Earn public API (/v1) drives the full strategy lifecycle over HTTP:
browse vaults, create a strategy, fetch ready-to-sign approval and
deposit/withdraw calldata, broadcast it, and poll to completion.
Lifecycle
GET /v1/config: chains, minimum sizes, contract address.GET /v1/wallets/{addr}/balances: where the USDC is.GET /v1/vaults/GET /v1/vaults/rankings: pick vaults or preview an allocation.POST /v1/wallets/{addr}/tosthenGET /v1/wallets/{addr}/approvals: one-time consent, then sign any missing approvals.POST /v1/strategies: create.POST /v1/strategies/{id}/calldata/deposit: broadcast the returned transaction.GET /v1/strategies/{id}(+/performance,/history,/bridges,/intents/{intentId}): monitor.POST /v1/strategies/{id}/calldata/withdraworDELETE /v1/strategies/{id}: close.
Auth model
- Reads are public, rate-limited per IP.
- Writes are SIWE-signed. Create/update/delete and wallet-pref writes
carry a per-action Sign-In-With-Ethereum proof in the request body; the
recovered wallet (not any body field) is the authoritative owner. The
SignedRequestcomponent documents the exact message format. - Calldata endpoints are public (no SIWE). The on-chain signature is the real authorization boundary; rate limiting (per strategy + IP) is the abuse control.
- An
apikeyheader is required on every request. The key is public by design; seecomponents.securitySchemes.
Units
- Read models (
/v1/vaults,/v1/strategies, detail, history, bridges) return decimal JSON numbers for USDC values:total_value_usdc: 1234.56means 1,234.56 USDC. - APY fields are percentage numbers, not fractions:
apy: 5.423means 5.423% APY. Realized APY is unbounded and may be negative. - Transaction and approval templates (
transactions[],approvalsNeeded[], balances, approvals) carry base-unit strings: USDC is a 6-decimal integer string ("1000000"= 1 USDC), native gas is wei, shares and allowances are raw uint256 decimal strings. Strings so values above 2^53 never lose precision.
Stability
v1 is additive-only: new optional fields and endpoints may appear;
existing fields will not change type or disappear without a version bump.
One launch-week exception (2026-07-20): vault rankings moved to
GET /v1/vaults/rankings, wallet approvals became multi-chain, and live
vault liquidity folded into the vault detail read.
SIWE hardening (2026-07-21, v1.2.0): signed messages carry a - path:
Resources entry binding the proof to the request path, and nonces are
single-use. A proof without a matching - path: entry is rejected with
siwe_payload, and nonce reuse is rejected with siwe_replay.
SignedRequest has the rules.
APY-gap floors (2026-07-28, v1.3.0): both threshold fields now carry
hard minimums: same-network >= 3 and effective cross-network >= 5,
rising to 5/7 when the strategy's networks include Ethereum. Values
below a floor are rejected with a 400. An omitted delta_pct on create
now defaults to the same-network floor (previously a legacy 0.1);
strategies created before the floors keep running unchanged until an
update touches a threshold field.
Strategy leaderboard (2026-08-05, v1.6.0): GET /v1/strategies/leaderboard
returns every eligible strategy ranked by realized APY computed over
TOTAL contributed capital (initial deposit plus later top-ups), so a
mid-life deposit can never masquerade as yield. One dataset: time-span,
network, and duration filtering is client-side. Wallets are server-side
truncated in the board response.
APY-gap guardrails relaxed (2026-08-06, v1.7.0): the v1.3.0 chain-tier
floors are gone. Both threshold fields accept any value >= 0.25
(cross_chain_delta_pct also keeps its 0 inherit sentinel); the old
recommended ranges are UI-side warnings only. An omitted delta_pct
on create still defaults to the recommended bar (3, or 5 with
Ethereum). PATCH validates only the threshold fields present in the
payload; stored values are never re-validated.
Clone tracking (2026-08-06, v1.8.0): POST /v1/strategies accepts an
optional cloned_from strategy id. Lineage is recorded only when the
created strategy's settings match the source's (the capital amount,
name, and funding chain are the cloner's own and never count as edits),
and a clone of a clone is attributed to the original; an edited clone
stores nothing and is a normal strategy. A later PATCH that changes any
compared setting severs lineage on the edited strategy and on its
clones. Leaderboard rows carry the new clone_count (how many
strategies currently record that row as their clone source) and
cloned_from (the original a clone row points at, null for
originals).
Per-strategy TVL exit ratio (2026-08-11, v1.9.0): min_tvl_exit_ratio
(create/update, default 0.75) sets the held-vault TVL exit floor as
min_tvl_usd × ratio: fresh entries still gate at the full 1x
min_tvl_usd. 0 disables the TVL exit. Participates in the clone-lineage
comparison alongside the other config fields.
Dollar config levels (2026-08-13, v1.10.0): min_tvl_exit_usd and
min_liquidity_entry_usd are the new absolute-dollar source of truth for
the TVL exit floor and the liquidity entry level. min_tvl_exit_ratio
and min_liquidity_entry_multiplier become deprecated aliases: still
accepted on writes and returned on reads, always kept consistent with the
dollar fields. A request carrying a dollar field AND its alias is a 400.
PATCH semantics changed with the dollar truth: moving a base value
(min_tvl_usd / min_liquidity_usd) alone no longer moves the derived
dollar level; the alias is re-derived instead (clamped/normalized where
the pair would invert). Legacy clients that send the alias on every save
keep their old behaviour, because a sent alias resolves against the
effective post-patch base.
Longer time windows (2026-08-15, v1.11.0): two precomputed APY windows
join the ladder: 12h and 24h (windows.h12/h24 on vault reads,
apy12h/apy24h on the series). The window and apySmoothingMinutes
params accept up to 1440. Create defaults for an omitting client move:
delta_confirmations 10 → 12 (60 min) and apy_smoothing_minutes
30 → 360. Stored values on existing strategies are unchanged.
Force-exit reason (2026-08-16, v1.12.0): history entries in the force
categories carry a nullable force_reason (liquidity_exit |
tvl_exit) naming which floor drove the exit. NULL on rows written
before this version and on non-floor force exits; no backfill.
Capital validation (2026-09-10, v1.13.0): capital_usdc must be a finite
number above 0 on create and, when present, on PATCH. Create also
rejects a capital below the per-chain minimum of any chain in
chain_ids. Both fail with 400 invalid_request.