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

  1. POST /api/auth/challenge with { "wallet": "<address>" } returns { id, message, expiresAt }.
  2. Sign message with the wallet's key, exactly as given.
  3. POST /api/auth/verify with { "challengeId", "wallet", "signature" }, the signature in base64. The response sets the ditto_session cookie for 24 hours.

GET /api/auth/session returns whose session it is; POST /api/auth/logout ends it.

Read

RequestReturns
GET /api/protocol/configProgram, collateral mint, policy and chainTime, the cluster's clock
GET /api/protocol/seriesEvery series, with balances and settlement
GET /api/protocol/vaultsEvery Ditto Spot vault
GET /api/protocol/auctionsEvery 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/healthDatabase, chain, worker and index status

All amounts are decimal strings of whole units: six-decimal USDC and prices, whole LONG and SHORT.

Act

  1. POST /api/protocol/prepare with { "idempotencyKey", "action", "params" }. The response is an intent: its id and one or more unsigned transactions, in base64.
  2. Sign every transaction with your key, without changing it.
  3. POST /api/protocol/confirm with { "intentId", "signatures" }, the signatures in order, before you broadcast.
  4. Send each transaction to Solana in order, then call confirm again until the intent reads FINALIZED.
ActionParams
openSeriesfeedId, lower, upper, expiry; optional publishTime to open on that exact Pyth print
mintPairsseries, units, maxTotalCost
mergePairsseries, units, minCollateral
settleSeriesseries
redeemseries, units, longSide, minCollateral
createVaultseries
depositVaultvault, units, minShares, maxCash
withdrawVaultvault, shares, minLong, minCash
startRollvault, nextSeries
placeOffervault, units, price
cancelOffervault, offer
finalizeRollvault
retryAuctionvault
recoverAuctionvault, 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.