Skip to content

Sandbox Environment

The Sarna sandbox is a mock API that returns static, deterministic responses for all documented endpoints. Use it to build and test integrations without touching production data.

Overview

  • Deterministic responses: Same input always produces the same output
  • Bearer token auth: Simple Authorization: Bearer <token> — no HMAC signing
  • Two-tier access: Standard tokens for trading/market data, admin tokens for /v1/admin/*
  • 148 endpoints: Golden workflow endpoints return full data; remaining return placeholder responses
  • Rate limit: 100 requests/minute per token

Credentials

Token Access Level Endpoints
sandbox_test_xxxx12345 Standard All /v1/* except /v1/admin/*
sandbox_admin_xxxx67890 Admin All endpoints including /v1/admin/*

Standard tokens accessing admin endpoints receive a 403 Forbidden with upgrade guidance.

Generate Your Own Key

Create a personalized sandbox API key tied to your email.

Manage API Keys

Getting Started

1. Set your base URL and token

BASE_URL=https://sarna-sandbox-api.sarna.workers.dev
TOKEN=sandbox_test_xxxx12345

2. Make your first request

curl -H "Authorization: Bearer $TOKEN" $BASE_URL/v1/quotes/AAPL

3. Check the response

{
  "Errors": [],
  "Warnings": [],
  "HasData": true,
  "Quote": {
    "Symbol": "AAPL",
    "CompanyName": "Apple Inc.",
    "LastPrice": 187.50,
    "BidPrice": 187.48,
    "AskPrice": 187.52,
    "Volume": 52340000,
    "Timestamp": "2026-03-28T15:59:59Z"
  }
}

Golden Workflow: Quote → Order → Fill → Positions

The canonical trading workflow in four steps:

Step 1: Get a Quote

curl -H "Authorization: Bearer $TOKEN" \
  $BASE_URL/v1/quotes/AAPL

Returns current bid/ask/last price for the symbol.

Step 2: Place an Order

curl -X POST -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"Symbol":"AAPL","Side":"Buy","Quantity":100,"AccountId":"500123"}' \
  $BASE_URL/v1/orders

Returns a new order with status Pending. Note: LimitPrice is negative for buys (debit = money out).

Step 3: Check Order Status

curl -H "Authorization: Bearer $TOKEN" \
  $BASE_URL/v1/orders/ORD-001

Dynamic orders (from Step 2) return as Filled on subsequent GET.

Step 4: Verify Positions

curl -H "Authorization: Bearer $TOKEN" \
  $BASE_URL/v1/accounts/500123/positions

Returns all positions for the account with market values.

Test Data

Accounts

Account ID Type Description
500123IndividualPrimary test account (used in golden workflow)
500124JointJoint account with TSLA and AMZN positions
500125IRARetirement account (restricted trading)
500199InstitutionalAdmin test account

Available Symbols

Symbol Company Last Price Bid Ask
AAPLApple Inc.$187.50$187.48$187.52
GOOGLAlphabet Inc.$141.80$141.78$141.82
MSFTMicrosoft Corp.$378.25$378.20$378.30
TSLATesla Inc.$248.90$248.85$248.95
AMZNAmazon.com Inc.$178.35$178.30$178.40

Pre-loaded Orders (Account 500123)

Order ID Symbol Side Qty Status Price
ORD-001AAPLBuy100Filled-$187.50
ORD-002GOOGLBuy50Filled-$141.80
ORD-003MSFTSell25Pending$378.25

Prices follow sign conventions: negative = debit (buy), positive = credit (sell).

Behavior Notes

  • Stateful orders: Orders created via POST return as Filled on subsequent GET
  • State resets: Dynamically created orders expire after 24 hours. Pre-loaded data is always available.
  • Rate limiting: 100 requests/minute per token. Returns 429 with Retry-After header.
  • Unknown accounts: Return 403 Forbidden (not 404) for security.
  • Placeholder endpoints: Unimplemented endpoints return 200 with HasData: false and a warning.
  • PascalCase fields: All response fields use PascalCase (AccountId, not accountId).
  • UTC timestamps: All timestamps are UTC in ISO 8601 format.

Common Errors

Status Code Cause Fix
401UNAUTHORIZEDMissing or invalid tokenAdd Authorization: Bearer sandbox_test_xxxx12345
403FORBIDDENStandard token on admin endpointUse sandbox_admin_xxxx67890
404NOT_FOUNDUnknown symbol or order IDCheck available symbols/orders in test data above
400INVALID_REQUESTMissing required fieldsCheck error message for required fields
429RATE_LIMITEDToo many requestsWait 60 seconds, use exponential backoff

Resources