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
POSTsends JSON, under 16 KiB, with anOriginheader 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
POST /api/auth/challengewith{ "wallet": "<address>" }returns{ id, message, expiresAt }.Sign the exact UTF-8
messagewith the wallet's Ed25519 key.POST /api/auth/verifywith{ "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
| Endpoint | Returns |
|---|---|
GET /api/scrips | Every 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/reserve | The reserve, valued at its authenticated prices |
GET /api/reserve/state | The reserve's roles and settings as recorded, without a valuation |
GET /api/network | The cluster, program and USDC mint the API settles on, and waiting until the program is deployed |
GET /api/wallet | Signed in: your USDC and Scrip balances and your recent transactions |
GET /api/health | Readiness of the database, the chain, the worker and the keeper scheduler, as status: ready, waiting or unavailable |
Act
POST /api/transactions/preparewith{ "idempotencyKey", "action" }returns a transaction intent with the unsignedtransaction(base64) and its status.Sign the transaction with the wallet. An
issuetransaction arrives already signed by its new mint account: add the wallet's signature beside it (with@solana/web3.js,partialSign;signwould drop the mint's signature).POST /api/transactions/{id}/submitwith{ "signedTransaction": "<base64>" }. Scrip stores it, then sends it.Poll
GET /api/transactions/{id}untilstatusisfinalizedorfailed.
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
| Code | Meaning |
|---|---|
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. |