Reference
API for wallets and agents
Read the protocol and send every action over HTTP, signed by your own key.
The app is built on a public HTTP API. A wallet or an agent can do everything the app does: the server builds each transaction, your key signs it, and you send it to Solana yourself.
Sign in
POST /api/auth/challengewith{ "wallet": "<address>" }returns{ id, message, expiresAt }.- Sign
messagewith the wallet's key, exactly as given. POST /api/auth/verifywith{ "challengeId", "wallet", "signature" }, the signature in base64. The response sets theditto_sessioncookie for 24 hours.
GET /api/auth/session returns whose session it is; POST /api/auth/logout ends it.
Read
| Request | Returns |
|---|---|
GET /api/protocol/config | Program, collateral mint, policy and chainTime, the cluster's clock |
GET /api/protocol/series | Every series, with balances and settlement |
GET /api/protocol/vaults | Every Ditto Spot vault |
GET /api/protocol/auctions | Every roll offer; filter with ?vault= |
GET /api/protocol/portfolio?wallet= | A wallet's SOL and token accounts |
GET /api/protocol/price?feedId= | Pyth's price at the chain clock, in six-decimal units, with its publish time |
GET /api/health | Database, chain, worker and index status |
All amounts are decimal strings of whole units: six-decimal USDC and prices, whole LONG and SHORT.
Act
POST /api/protocol/preparewith{ "idempotencyKey", "action", "params" }. The response is an intent: itsidand one or more unsignedtransactions, in base64.- Sign every transaction with your key, without changing it.
POST /api/protocol/confirmwith{ "intentId", "signatures" }, the signatures in order, before you broadcast.- Send each transaction to Solana in order, then call
confirmagain until the intent readsFINALIZED.
| Action | Params |
|---|---|
openSeries | feedId, lower, upper, expiry; optional publishTime to open on that exact Pyth print |
mintPairs | series, units, maxTotalCost |
mergePairs | series, units, minCollateral |
settleSeries | series |
redeem | series, units, longSide, minCollateral |
createVault | series |
depositVault | vault, units, minShares, maxCash |
withdrawVault | vault, shares, minLong, minCash |
startRoll | vault, nextSeries |
placeOffer | vault, units, price |
cancelOffer | vault, offer |
finalizeRoll | vault |
retryAuction | vault |
recoverAuction | vault, nextSeries |
The same idempotency key always returns the same intent, so a retry after a dropped connection never builds a second action. While a signed intent on a series or vault is unfinished, a new one on the same series or vault waits for it: resume it with GET /api/protocol/transactions/<id>.
SDK
src/sdk/client.ts in the Ditto repository wraps all of this: authenticateWallet, then executeIntent(client, wallet, action, params) signs, simulates, sends and waits for finality in one call.