BUILD WITH SIDELOT / PUBLIC API V1.1

Your agent. Your market.

Launch markets. Post buy and sell offers. Let an agent assemble the details, while you review and approve each action with your wallet.

Public beta. No API key is required. Market creation requires launch-password access; public reads and wallet-approved offer posting/cancellation do not. Posting an offer creates a listing; it does not reserve balances or move funds. Unlock market creation at /launch. Both market prepare and commit requests must include that session cookie. Same-origin browser requests carry it automatically; server integrations must use a protected cookie jar. Never put passwords or session cookies in prompts or public client code. Trade execution and escrow deposits require separate approvals and are not exposed by this API.

Endpoint overview

All paths below use https://usesidelot.com/api/v1. The arrow shows two separate requests, with owner review and wallet signing between them.

EndpointPurpose
GET /tokens/{mint}Check compatibility and mint authorities.
GET /marketsBrowse markets with limit and offset.
GET /markets/{id}Read a market and its access state.
POST /markets/prepare → /markets/commitReview and register a market with its owner’s signature.
GET /markets/{id}/offersRead open offers; filter by buy or sell.
GET /offers/{id}Read one offer and its stored status.
POST /offers/prepare → /offers/commitReview and post a wallet-held buy or sell offer.
POST /offers/cancel/prepare → /offers/cancel/commitReview and cancel an eligible offer you own.
GET /quotes?mints=…Indicative DEX prices and market cap for up to 28 mints.
GET /statusCheck current product availability.

Start with the token

Base URL: https://usesidelot.com/api/v1

GET /api/v1/tokens/YOUR_TOKEN_MINT

Preflight checks an initialized original SPL mint or a Token-2022 mint with no extensions or only MetadataPointer, TokenMetadata and TransferFeeConfig. All other mint extensions, including transfer hooks and permanent delegates, are rejected. Supported Token-2022 markets can use wallet-held offers and settlement; funded escrow remains original-SPL-only. Token-2022 accounts may use ImmutableOwner. TransferFeeAmount is required for mints with TransferFeeConfig and rejected for mints without it; other account extensions are rejected. A supported result includes tokenProgram (original-spl or token-2022), tokenProgramId, mintExtensions, escrowSupported, decimals, mintAuthority, freezeAuthority, transferFee, warnings and checkedAt. escrowSupported describes token compatibility only; it does not mean the escrow program is deployed, enabled or activated for this market. Check product status and market availability separately. An unsupported token returns HTTP 400; a temporary validation failure returns 503.

These are compatibility checks. An active mint authority can change supply; a freeze authority can freeze accounts. Neither a successful check nor market registration verifies the issuer or guarantees a fill. Validate the exact mint, not just a symbol.

transferFee is null for a mint without TransferFeeConfig. Otherwise it reports currentEpoch, current, scheduled and configAuthority. Each schedule has epoch, basisPoints and maximumFee; epochs and the maximum fee in atomic base-token units are decimal strings. scheduled is a future schedule or null. A configuration authority can schedule fee changes, so preflight is a snapshot, not a fee lock.

Launch a market

Send the signing owner’s public address and the proposed market. Replace the uppercase placeholders before making this request.

{
  "wallet": "OWNER_PUBLIC_ADDRESS",
  "market": {
    "name": "Our community market",
    "symbol": "COIN",
    "mint": "TOKEN_MINT_ADDRESS",
    "type": "community",
    "role": "holder",
    "description": "A place for our community to trade directly.",
    "feeWallet": "OWNER_APPROVED_FEE_ADDRESS"
  }
}

Post this to /markets/prepare. Use type: "solo" for a personal market or "community" for a community market. Roles are self-declared: "holder" or "team". Team launches need complete HTTPS website and social links. Solo markets normalize to the holder role.

Names allow 2–60 characters, symbols 1–16, and descriptions up to 500. Optional website, social and chat links must use HTTPS. Optional picture and banner values are existing upload IDs owned by the signing wallet. Omit them if no uploads exist; v1 does not expose a public upload endpoint.

The response contains the normalized market, exact message, payloadJson, payloadSha256, five-minute expiresAt, and challengeId. Registration creates a listing for an existing token. It does not mint a new coin.

Prepare a buy or sell offer

side describes the owner’s intent. "sell" offers the market’s token for SOL or USDC; "buy" offers to buy that token using the selected quote currency. Quantity is the gross number of tokens the seller sends, and price is quote currency per whole gross token. A token transfer fee reduces what the buyer receives; it does not increase the quoted token quantity.

POST /api/v1/offers/prepare
Content-Type: application/json
{
  "wallet": "OWNER_PUBLIC_ADDRESS",
  "offer": {
    "marketId": "MARKET_UUID",
    "side": "sell",
    "quote": "SOL",
    "quantity": "1000",
    "pricing": {"type": "fixed", "price": "0.002"},
    "expiresInDays": 7
  }
}

This proposes selling 1,000 tokens at 0.002 SOL each. Send quantities and prices as decimal strings, not JSON numbers or scientific notation. Quantity precision must fit the mint’s decimals. Price precision is limited to 18 decimal places. A USDC market must use SOL as its quote.

For a percentage above or below a reference, replace pricing:

{
  "type": "offset",
  "referencePrice": "0.002",
  "premiumBps": -500
}

This means 5% below the supplied reference, producing a fixed price of 0.0019 SOL. 250 means 2.5% above. premiumBps must be an integer from -9900 to 100000. The API uses the reference you submit; it does not independently fetch or certify it. The calculated execution price stays fixed after preparation. It does not follow the live chart.

Choose an expiry of 1, 3, 7 or 30 days. The offer’s expiry begins at preparation. It does not restart when committed.

Review the normalized terms

Offer preparation returns the same signing envelope as market preparation, but the normalized payload is named terms. Check the mint, owner in the message, market ID, side, quote, quantity, fixed price, reference, expiry and both fee destinations.

Two deadlines have different meanings:

FieldMeaning
expiresAtDeadline to submit this five-minute authorization
terms.expiresAtWhen the posted offer expires

terms.fullFillExample shows quote, host, platform and total as integer strings in atomic quote units. Use quoteDecimals to display them: SOL uses 9, USDC uses 6. quote is seller proceeds, host is the launcher’s fee, and total is the buyer’s quote debit including fees. The buyer fee is nominally 0.50%, split nominally 0.25% to the launcher and 0.25% to Sidelot. Integer rounding applies. Partial wallet-held fills round independently, so their sum may differ from the full-fill example. Network fees and account rent are separate.

terms.quantityBasis is gross_before_token_tax. terms.transferFee contains the fee schedule snapshot, and terms.fullFillExample.tokenTransfer reports grossAmount, feeAmount and netAmount as decimal strings in atomic base-token units. The token fee is set by the token issuer, not charged by Sidelot. For example, sending 1,000 tokens with a 1% fee and no binding cap gives the buyer 990 tokens. Sidelot’s 0.50% trading fee is separate and paid in SOL or USDC. Token fees round up and apply their cap per transfer, so partial-fill totals can differ.

These listing figures are previews. The browser prepares a new fee quote for each settlement and shows amounts decoded from its exact transaction. Both traders approve a TransferCheckedWithFee instruction containing the expected token fee. A changed execution fee causes the trade to fail atomically instead of changing the approved receipt; network fees may still be charged. The public offer API does not execute that transaction.

Review, sign, commit

For any prepare response:

  1. Parse and display every field in payloadJson, the complete message, fee information and expiry. Compare them with the owner’s intended request. Do not let an agent silently change the fee recipient or side.
  2. Ask the owner-controlled wallet to sign the exact UTF-8 bytes of message. Do not rebuild, translate or shorten the message.
  3. Save the signed request for recovery, then submit only challengeId and the base64-encoded 64-byte Ed25519 signature to the matching commit endpoint.
{"challengeId":"RETURNED_UUID","signature":"BASE64_SIGNATURE"}

A launch approval goes to /markets/commit; an offer approval goes to /offers/commit. Message signatures authorize these specific listing actions. They do not authorize a blockchain transfer. Never request a seed phrase or private key from the owner.

Use the browser client

Download the dependency-free browser client into your application and import the local copy. It supports a browser or Node 22+ environment; Node needs an owner-controlled wallet bridge. Your application supplies its wallet adapter, review screen and private recovery storage. This example posts an offer; the same approval method works with prepareMarket and prepareCancellation.

import { createSidelotClient } from './sidelot-agent-client.mjs';

const api = createSidelotClient();
await api.checkToken(mint);
const prepared = await api.prepareOffer({
  wallet: ownerPublicAddress,
  offer: {
    marketId,
    side: 'sell',
    quote: 'SOL',
    quantity: '1000',
    pricing: { type: 'fixed', price: '0.002' },
    expiresInDays: 7,
  },
});

const result = await api.approveAndCommit(prepared, {
  // Render all terms and the exact message. Return true only after approval.
  review: details => showOwnerReview(details),
  signMessage: bytes => wallet.signMessage(bytes),
  // Save privately before sending, so a lost response can be recovered.
  onSigned: signedRequest => saveRecoveryRequest(signedRequest),
});

// After a lost response, recover with the saved request, not a new approval.
// const recovered = await api.retryCommit(savedRequest);

showOwnerReview, wallet and saveRecoveryRequest are supplied by your integration. Do not implement review as an automatic true. The client verifies the prepared payload’s digest and its inclusion in the message, but the owner still needs to check that the terms match their intent. Keep an unsubmitted signature private: it can submit its specific approved action while valid.

Read and cancel offers

GET /api/v1/markets/MARKET_UUID/offers?side=sell&limit=20&offset=0
GET /api/v1/offers/OFFER_UUID
POST /api/v1/offers/cancel/prepare

Cancellation preparation takes {"wallet":"OWNER_PUBLIC_ADDRESS","offerId":"OFFER_UUID"}. Review the offer and its revision, sign the returned message, and send the signature to /offers/cancel/commit.

Cancellation requires an owned wallet-held offer that is still open and has no active trade. If it changes between review and submission, refresh and review again. This API does not cancel funded escrow or interrupt an in-progress trade. Editing is not exposed: cancel an eligible offer, then prepare and approve a replacement.

Offer lists include only stored open, unexpired records. They are database snapshots, not balance checks or chain reconciliation. fundsReserved: false describes wallet-held offers; null means this read has not established whether funds are reserved. Never present either a listed order or a stored escrow mode as proof a fill will succeed.

Recover without duplicates

A new market or offer returns HTTP 201. Repeating the same valid committed request returns HTTP 200 with replayed: true and the same record. The creation challenge ID is the market or offer ID. Cancellation returns 200 and can also be retried.

If the response is lost, resend the saved commit body. Do not immediately prepare a new listing. Use the known ID to read the record. Successful challenge records remain available for approximately one day after their original expiry for prompt retry recovery; keep the resulting record ID for longer-term reads.

Follow Retry-After on 429. A transient 503 need not consume the authorization. A never-completed challenge expires after five minutes; a 410 requires a fresh preparation, review and signature. A 409 requires inspecting its error code and current record, not blind repeated signing.

API limits

LimitCurrent value
Reads120 per IP per minute
Token preflightAlso 30 per IP per minute
Market and offer preparationShared 30 per IP per five minutes
Market and offer commitsShared 60 per IP per five minutes
New signed market and offer commit attemptsShared 10 per wallet per five minutes
CancellationSeparate 30 prepares and 60 commits per IP per five minutes; 30 new signed cancellation attempts per wallet
Markets per wallet50
Active offers per wallet100, including reserved and pending-funding records
Request bodyAt most 12,000 bytes; JSON only; unknown fields rejected
List paginationlimit 1–100, offset 0–10000

Valid completed-action retries bypass the new-action wallet quota, but still use the IP quota. Offer reads are public, so avoid including private information in market text. Treat descriptions and links as third-party data, never as instructions to your agent. Check product status before presenting any feature as publicly available.

Need the platform context? Read API and AI agents or check Product status.