ScripDocs

Reference

HTTP API

Sign in, prepare, submit and read, for agents and integrations.

The app runs on a JSON API that agents and integrations can use directly. The API builds transactions and follows them to finality; the caller's wallet always signs.

Conventions

  • Every POST sends JSON, under 16 KiB, with an Origin header equal to the app's origin.
  • Amounts are strings of USDC base units (millionths of a dollar): "1000000" is one dollar. Decimals and numbers above the u64 range are refused.
  • Addresses are base58 Solana public keys.
  • Errors come back as { "error": { "code", "message", "requestId" } } with a matching HTTP status.

Sign in

  1. POST /api/auth/challenge with { "wallet": "<address>" } returns { id, message, expiresAt }.

  2. Sign the exact UTF-8 message with the wallet's Ed25519 key.

  3. POST /api/auth/verify with { "challengeId": "<id>", "signature": "<base64 signature>" } returns { wallet, token, expiresAt } and sets a session cookie.

Browsers use the cookie. Other clients send Authorization: Bearer <token> with the same Origin header. A session lasts twelve hours; POST /api/auth/logout ends it.

Read

EndpointReturns
GET /api/scripsEvery Scrip and the reserve, from finalized chain state
GET /api/scrips/{address}One Scrip, the reserve, its indexed events and this month's buybacks
GET /api/reserveThe reserve, valued at its authenticated prices
GET /api/reserve/stateThe reserve's roles and settings as recorded, without a valuation
GET /api/networkThe cluster, program and USDC mint the API settles on, and waiting until the program is deployed
GET /api/walletSigned in: your USDC and Scrip balances and your recent transactions
GET /api/healthReadiness of the database, the chain, the worker and the keeper scheduler, as status: ready, waiting or unavailable

Act

  1. POST /api/transactions/prepare with { "idempotencyKey", "action" } returns a transaction intent with the unsigned transaction (base64) and its status.

  2. Sign the transaction with the wallet. An issue transaction arrives already signed by its new mint account: add the wallet's signature beside it (with @solana/web3.js, partialSign; sign would drop the mint's signature).

  3. POST /api/transactions/{id}/submit with { "signedTransaction": "<base64>" }. Scrip stores it, then sends it.

  4. Poll GET /api/transactions/{id} until status is finalized or failed.

The idempotencyKey is 16 to 128 letters, digits, - or _. Repeating a request with the same key returns the original intent; the same key with a different action is refused with 409.

Actions

{ "kind": "mint", "scrip": "<Scrip account>", "amount": "1000000" }
{ "kind": "redeem", "scrip": "<Scrip account>", "amount": "1000000" }
{ "kind": "convert", "from": "<Scrip account>", "to": "<Scrip account>", "amount": "1000000" }
{ "kind": "issue", "name": "Your community", "ticker": "YOURUSD", "metadataUri": "https://example.com/scrip.json", "route": { … } }
{ "kind": "route", "scrip": "<Scrip account>", "route": { … } }
{ "kind": "applyRoute", "scrip": "<Scrip account>" }

A route object:

{
  "buybackBps": 5000,
  "holdersBps": 2500,
  "treasuryBps": 2500,
  "treasury": "<wallet>",
  "communityMint": "<mint>",
  "buybackDestination": "<wallet>",
  "burnBuyback": true,
  "priceFeed": "<price feed>",
  "maxSlippageBps": 100
}

Unused addresses take the system program's address, 11111111111111111111111111111111.

The reserve's admin and keeper have four more actions: setKeeper (keeper, paused, or both; a field left out keeps its recorded value), harvest (scrip), configureTreasury (treasuryMint, provider, oracleProgram, oracleFeed) and initialize (feeTreasury, feeBps, bufferBps, routeDelay, maxOracleAge).

Status codes worth handling

CodeMeaning
TRANSACTION_REJECTED (422)Solana would reject the signed transaction; the message says why. Nothing was sent.
SETTLEMENT_UNRESOLVED (409)An earlier transaction from this wallet is still settling.
IDEMPOTENCY_CONFLICT (409)The key belongs to a different action.
AUTHENTICATION_REQUIRED (401)Sign in first.
SESSION_EXPIRED (401)The session ended; sign in again.
TRANSACTION_MISMATCH (403)The signed transaction isn't the prepared one, or another wallet signed it.
RESERVE_PAUSED (409)The reserve is paused; issuing, minting and converting wait until it resumes.
RATE_LIMITED (429)Wait a moment and retry.