Skip to content
Anyperp
DocsAPIAppData
Open the app

Using Anyperp

Getting startedTradingFees, funding and the borrow feeProviding liquidityClaim balancesListing a marketHow prices are madeHalts and settlementAPITokenFAQ

Papers

LitepaperWhitepaper

API

Everything the app shows comes from Anyperp's public HTTP API: markets, rounds and their signatures, the index series, the vault, protocol parameters and the attested listener data. Public reads need no sign-in and no key. Wallet reads and signed actions use the same session the app uses.

Base URL and versions

The API's base URL is <API base URL>, and every path starts with /v1. The full description of every operation is served as OpenAPI at <API base URL>/v1/openapi.json and as JSON Schema at <API base URL>/v1/schema.json.

curl "<API base URL>/v1/markets?state=live&limit=20"

Responses and errors

A successful response wraps its data with metadata:

{
  "data": { "items": [], "nextCursor": null, "total": 0 },
  "meta": {
    "requestId": "8f1c2b9e-0d4a-4e57-9a51-3f6d2f1e7c10",
    "asOf": "2026-10-16T12:00:00.000Z",
    "mode": "indexed",
    "contractVersion": "1.0.0"
  }
}

Collections are pages of { items, nextCursor, total }. Pass nextCursor back as cursor for the next page; limit takes 1 to 100. Data read from the chain is served from finalized state.

An error has one shape everywhere:

{
  "error": {
    "code": "NOT_FOUND",
    "message": "The requested resource was not found.",
    "retryable": false,
    "details": { "resourceId": "..." }
  },
  "meta": { "requestId": "...", "asOf": "...", "mode": "indexed", "contractVersion": "1.0.0" }
}
CodeHTTPMeaning
VALIDATION_ERROR400the input is malformed; details.issues names each field
UNAUTHORIZED401the request needs a signed-in wallet, or the sign-in failed
SESSION_EXPIRED401the session has ended; sign in again
GEO_BLOCKED403trading isn't available where the request comes from
FORBIDDEN403the request isn't allowed for this caller
NOT_FOUND404no such resource
CONFLICT409the request conflicts with current state, such as a second pending order on one position
MARKET_NOT_TRADABLE409the market or side isn't taking new orders
ORDER_NOT_CANCELLABLE409the order can still fill
WITHDRAWAL_LOCKED409the withdrawal hasn't unlocked or been priced
QUOTE_EXPIRED409the quote is older than its expiry
RATE_LIMITED429too many requests; retryAfterSeconds says when to retry
CAP_EXCEEDEDin a quotethe size doesn't fit under the side's cap or the vault's reserve
TRANSACTION_FAILEDin a transactionthe transaction failed on chain

retryable says whether the same request can succeed later.

Units

ValueEncoding
USDC amountsinteger strings in base units, 6 decimals: "1000000" is 1 USDC
Index, contract size, shares, ratesinteger strings in fixed-point with 9 decimals ("fixed9"): "600000000000" is 600.00
Notionalsize × index ÷ 10¹², in USDC base units; one contract is worth the index in USDC
Funding and borrow ratesper hour, fixed9; funding velocity per hour², fixed9
Basis points, counts, leverageJSON numbers
TimesISO 8601 strings in UTC

Amounts can exceed the range of a JavaScript number. Read them with BigInt or an exact decimal type. Signed values (PnL, skew, net exposure, accruals) carry a leading minus sign.

Public endpoints

MethodPathReturns
GET/v1/protocolprotocol parameters with their units and provenance, the fee split, units, attestation roots and chain addresses
GET/v1/marketsmarket summaries with state, index, 24 h change, open interest and caps, funding, borrow, next round and pauses; filter with state
GET/v1/markets/:marketIdone market with its metric spec, cost dossier, Sentinel flags, other venues, recent rounds, market parameters and settlement
GET/v1/markets/:marketId/seriesthe index history; interval is hour or day; by default the latest 168 hourly points in ascending time, limit 1 to 168, cursor pages back
GET/v1/markets/:marketId/roundsthe market's rounds with both observations; filter with state
GET/v1/rounds/:roundIdone round with fetch and source times, signers and signatures
GET/v1/vaultNAV, share price, shares, liquidity, net exposure, fees, insurance fund and the withdrawal queue
GET/v1/attested/subjectsevery artist with attested data, its latest value and its root agreement rate
GET/v1/attested/subjects/:subjectId/seriesan artist's daily attested series; from, to, cursor, limit
GET/v1/attested/comparetwo artists' series aligned; a, b, normalization (raw or rebased_100), from, to
GET/v1/proposalsproposals with bonds, shadow agreement, curator votes and listing times; filter with state
GET/v1/proposals/:proposalIdone proposal with its spec, cost dossier and Sentinel flags
GET/v1/statusservice liveness, each market's latest print and consecutive failed rounds, and halts
GET/v1/eligibilitywhether the visitor can trade, provide liquidity and propose, and the current terms version
GET/v1/sessionthe current wallet session, or anonymous
POST/v1/quotes/ordersa quote for an order: fill price, skew impact, fees, margin, liquidation price and room under the caps

A quote takes marketId, side, sizeFixed9 and leverage, and for a close intent: "close" with the positionId. It reports canSubmit and, when the order can't go through, a rejection in the error shape. A quote expires 60 seconds after it is made.

Wallet endpoints

These need the session cookie set at sign-in:

MethodPathReturns
GET/v1/me/ordersyour orders and whether each can be cancelled
GET/v1/me/positionsyour positions with accruals, margin, equity and liquidation price
GET/v1/me/lpyour shares, pending deposit, withdrawals and claim balances
GET/v1/me/proposeryour proposals, bonds and claimable proposer fees
GET/v1/me/historyfills, funding, borrow, liquidations, deposits, withdrawals, margin, bonds, fee claims and settlements
POST/v1/proposals/drafta Sentinel draft of a market spec and cost dossier
POST/v1/transactions/preparean unsigned transaction for an action
POST/v1/transactions/submitrecords the signature of a sent transaction
GET/v1/transactions/:transactionIdthe transaction's state

The live event stream

GET /v1/events is a server-sent event stream. Each message's event is the event type, its data the JSON event, and its id the event id. Filter market events with ?marketId=.

EventSent when
round.finalizeda round prints; carries the market and the round
order.filledan order fills; carries the market, order, position, round, side, size, fill price and fee, without the wallet address
market.state_changeda market changes state, such as probation to live
vault.updatedthe vault's NAV or queue changes
transaction.updatedone of your transactions changes state; needs your session
stream.resetthe stream can't resume from your position; refetch your reads

A heartbeat comment arrives every 15 seconds. A reconnecting EventSource sends Last-Event-ID and resumes where it left off; a new client can pass cursor. Events tell you what changed; read the endpoints again for the new state.

curl -N "<API base URL>/v1/events?marketId=<marketId>"

The contract package

@anyperp/contract is the API's TypeScript contract: every request and response type, the event union, the operation registry and a small client for browsers and Node 22.

import { createAnyperpClient, ApiClientError } from "@anyperp/contract";

const api = createAnyperpClient({ baseUrl: "<API base URL>" });

const markets = await api.request("markets", { query: { state: "live", limit: 20 } });
const first = markets.data.items[0];

const series = await api.request("marketSeries", {
  params: { marketId: first.id },
  query: { interval: "hour", limit: 168 },
});

try {
  await api.request("round", { params: { roundId: "unknown" } });
} catch (error) {
  if (error instanceof ApiClientError) console.log(error.status, error.response.error.code);
}

// Browser: live events through EventSource
const stop = api.subscribe(
  (event) => {
    if (event.type === "round.finalized") console.log(event.data.round.finalIndexFixed9);
  },
  { marketId: first.id },
);

request takes an operation name from the registry with its params, query and body, and throws ApiClientError with the status and the error envelope. eventsUrl gives the stream's URL for server-side consumers.

Signed actions

Every action that changes state is a Solana transaction signed in the user's wallet. The API prepares it and records it; it never holds a user's key.

AppAPIWalletSolanaIndexerprepare the actiontransaction, simulatedsign and sendtransactionsubmit the signaturefinalized logsprojection updatedlive event
The app asks the API to prepare a transaction, the wallet signs and sends it, the API confirms it, and the indexer projects the result.

Signing in

  1. GET /v1/eligibility returns termsVersion.
  2. POST /v1/auth/challenge with { wallet, origin }, the wallet's address and the app's origin, returns a challenge with the exact message to sign. It expires after 5 minutes.
  3. The wallet signs the message bytes with its message-signing feature.
  4. POST /v1/auth/verify with { challengeId, wallet, signatureBase64, nonUsPersonAttested, termsVersion } checks the Ed25519 signature and sets the HttpOnly session cookie.

POST /v1/auth/logout ends the session.

Prepare, sign and send, submit

  1. Prepare. POST /v1/transactions/prepare with { action, idempotencyKey }. The response carries the unsigned transaction (serializedTransactionBase64), its recentBlockhash and lastValidBlockHeight, the cluster, a plain description (unsignedMessageDescription), the required signers and the network fee in lamports.
  2. Sign and send. The wallet signs the transaction and sends it to Solana.
  3. Submit. POST /v1/transactions/submit with { transactionId, signature, idempotencyKey }. The API checks the transaction against the prepared message and returns its state: submitted, confirmed, failed or expired.

GET /v1/transactions/:transactionId and the transaction.updated event follow it to confirmation. For an order, orderId in the transaction matches the orderId of its order.filled event. A repeated request with the same idempotency key returns the same intent; the same key with different input is a CONFLICT.

Actions

kindFieldsWhat it does
open_orderquoteId, clientOrderId, marketId, side, sizeFixed9, marginUsdc, acceptablePriceFixed9escrows margin and queues an order for the next print; on the side you hold, it adds to the position
close_positionpositionId, sizeFixed9, acceptablePriceFixed9queues a close for the next print
cancel_orderorderIdcancels an order that can no longer fill and credits its margin to the claim balance
modify_marginpositionId, direction (add or remove), amountUsdcadds or removes margin at once
depositamountUsdcdeposits USDC into the vault at the next NAV
request_withdrawsharesFixed9queues a withdrawal for 72 h
execute_withdrawwithdrawalIdcredits a priced withdrawal's USDC to the claim balance
claim_balancesamountUsdc, sharesFixed9moves claim balances into the wallet; either may be "0"
propose_marketdraftId, bondUsdcposts the bond and proposes a drafted market
claim_market_feesmarketId, amountUsdc (optional)claims the proposer's fee share of a market; without an amount, all of it
PreviousHalts and settlementNextToken

On this page

Base URL and versionsResponses and errorsUnitsPublic endpointsWallet endpointsThe live event streamThe contract packageSigned actions
Anyperp
AppDataDocsLitepaperWhitepaperToken
Perpetual futures on artists’ monthly listeners, on Solana.Not offered to US persons.