GET /v1/health,
GET /v1/version, and GET /openapi.json). Everything else is
401 without a key.
Key prefixes pick the network
The first segment of a key encodes the cluster it can act on. The API loads the right RPC, scopes every database query, and rejects any attempt to reach across networks.| Prefix | Network | Use this when… |
|---|---|---|
lsh_test_* | solana-devnet | Building, integration tests, CI, demos. Free RPC, faucet stables. |
lsh_live_* | solana-mainnet | Production. Real money, mainnet RPC, mainnet receipts and explorer. |
lsh_test_* key cannot see a mainnet event, mainnet receipt, or
mainnet agent. A lsh_live_* key cannot see anything from devnet.
Searching a devnet signature with a lsh_live_* key returns 404
even though the signature exists on devnet — this is the explorer’s
isolation guarantee.
Issuing keys
Keys are issued out-of-band today — talk to us in Discord and we’ll mint one for the right network. Self-service issuance through a hosted dashboard is on the roadmap and ships in the same release as billing. The prefix is purely a routing hint and tells you which cluster the key acts on at a glance. The opaque tail is high-entropy; treat the full string as a secret.Per-request context
Two optional headers (or body fields, where supported) flow into every event row and receipt for traceability:| Field | Where it lives | Purpose |
|---|---|---|
Idempotency-Key | Header, on POST only | Replays the prior response if the same key is reused. See Idempotency. |
X-Leash-Client-Ref | Header, any method | Free-form caller reference. Stored on the event row, returned on lookup, surfaced in the explorer. |
client_reference | Body field on every prepare and submit endpoint | Same as the header. Body wins when both are set. |
Rate limits
Each API key gets a sliding-window quota that resets every minute. The default is generous and split per route family so a noisyPOST /v1/receipts flow can’t starve your prepare traffic.
Headers on every response:
429 with the same headers and a retry_after
field in the JSON body. The limiter is global across the API
fleet — retrying against a different region won’t get you more
budget.
Rotating and revoking
- Rotate — issue a new key, deploy it, then have us revoke the old one. There’s no client-side rotation flow yet.
- Revoke — keys can be flipped to
revoked_at = NOW()at any time. The next call returns401 invalid_api_key. - Audit — every authenticated call writes the (hashed) key id and
client_referenceonto the event row. Deleting a key does not delete its history.

