API
The Rising Tide REST API - base URLs, authentication, the response envelope, pagination, and the full endpoint reference.
The SDK is a typed client over this API, and everything it does is an HTTP call you can make yourself. If you are writing TypeScript, use the SDK - it carries the types, the BigInt handling and the transaction builders. This section is for everything else: another language, a server-to-server integration, or a case where you want to see exactly what is on the wire.
Base URLs
| Environment | Base URL |
|---|---|
| Testnet | https://testnet-api.risingtide.app |
| Mainnet | https://api.risingtide.app (planned) |
Authentication
Two headers, two independent questions. The full model is in Authentication.
X-API-Key: 3f8a1c02-9d47-4b6e-8f11-2c5a7e90d3b4
Authorization: Bearer <user session token>X-API-Keyidentifies your app. Send it on every request. Keys are opaque UUIDs with no prefix and no environment marker.Authorization: Beareridentifies the person acting, and is required only on routes that act as a user. That token is a Privy access token or a signed Stacks message.
The Auth column on every table in this section tells you which applies, per method:
| Column reads | What the request needs |
|---|---|
public | Nothing. No key and no session |
app key | The API key alone. Public read |
app key, user optional | The key. A session token, when sent, changes the answer |
app key + app access | The key. For an app behind an access gate, also a signed-in user holding an active grant |
app key + user | A valid user session too |
app key + user, entitlement | The user must also hold the entitlement for that action |
app key + user, app access | The user must hold an active access grant for your app |
app key + user, entitlement, app access | Both: the entitlement and an active access grant for your app |
user, user, entitlement | A valid user session (and the entitlement) and nothing else. These routes verify the session token and do not check the key |
A missing or invalid key is 401 on every route that checks one. A valid identity without the
right entitlement is 403 with code ENTITLEMENT_REQUIRED, and one without an access grant is
403 with code APP_ACCESS_REQUIRED - different failures, worth telling apart in your UI. Both
carry the missing piece in error.details.
A read-only key identifies the app but never authorizes a write on its own: a write under one must
also carry a verified session token, or it is a 401.
Response envelope
Every response, signing routes aside, is the same shape. data and error are both always
present, and exactly one is non-null.
{ "data": { "id": 42, "title": "morning rain" }, "error": null }{ "data": null, "error": { "code": "NOT_FOUND", "message": "SmartProduct 42 not found" } }error.details is present on validation failures. Codes and their meanings are in
API Errors.
One family differs. The server-signing routes under /api/privy/ answer
{ "success": true, "txId": "0x..." } on success and { "success": false, "error": "..." } on
failure, and a failed session check on them is a 401 with a bare { "error": "..." }. See
Contracts and Signing. The SDK's command surface normalizes all of
it.
Pagination
Paged list endpoints take page and limit, and nest their results under data:
{
"data": {
"items": [],
"pagination": { "page": 1, "limit": 20, "total": 137, "totalPages": 7 }
},
"error": null
}A few lists are shaped for what they hold instead: the notification feed pages with an opaque
cursor and returns nextCursor, and the small catalogs return the whole array.
Three conventions that will bite you
BigInts are strings. Anything the chain owns as a 128-bit integer - instanceId,
instanceNumber, feePaid - is serialized as a decimal string, not a JSON number. Parsing one
into a float will silently lose precision. Dates are ISO 8601 strings.
Unknown query parameters are rejected, not ignored. A listing route declares the params it
reads and 400s on anything else. A misspelled filter fails loudly instead of quietly returning
every row in the table, which is the failure that actually costs you.
include is an allowlist, and it is narrower on lists than on detail. A listing route will not
join per-row relations that would bloat the payload, so ?include=instances works on one product
and not on a page of them.
Rate limits
Every route sits behind a per-IP ceiling, and the surfaces that cost something carry tighter
limits of their own: signing, wallet creation, the faucets, contract generation, and the invite and
waitlist routes that a stranger can reach. The numbers are operator dials, so read the response
rather than hardcoding them. A limited request is 429 with code RATE_LIMITED and the back-off in
headers:
Retry-After: 42
RateLimit-Limit: 10
RateLimit-Remaining: 0
RateLimit-Reset: 42All four are exposed to cross-origin browser clients. The SDK surfaces a 429 as a typed
RateLimitError carrying retryAfterSeconds and does not wait and retry for you, because the
window can run to a minute: honoring the back-off is your call.
Health and maintenance
GET /api/health needs no key and is the one liveness check built for callers: it answers
{ timestamp, status, commit, services } with status of healthy, degraded or unhealthy, and
is a 200 only when healthy, 503 otherwise. commit is the git commit the deployment was built
from, or null where the platform does not report one. The SDK exposes it as health(). The detailed check is
operator-only.
When an operator puts the API into maintenance, every other route answers 503 with code
MAINTENANCE until it is lifted. Treat that as a scheduled pause, not a fault: render your own
maintenance state and retry later.
Versioning
The API is unversioned today. Breaking changes are announced in the Changelog and coordinated with SDK releases.
Reference
Every endpoint on the integration surface, grouped by what it acts on:
- Smart Products - create, read and publish products; read their contributions, editions and payments
- Editions and Payments - minted editions, transaction follow-up, payment legs
- Users and Collections - identity, ownership, earnings, app access, curated collections
- Invites - mint, assign, send, claim
- Contracts and Signing - generate Clarity source, serve token URIs, server-sign for custodial users
- Styles and Stickers - style sets, rendering, the artist economy
- Catalog and Reference Data - product types, apps, tags, causes, domain routes, lookups
Operator routes are not documented here. /api/admin/* authorizes on the signed-in person: the
session token must resolve to a user whose role holds the route's operator entitlement, which
no app-scoped key can supply. Scheduled workers authorize on a server-side secret. Neither is part
of the integration surface.