Conventions
A handful of patterns appear across the entire API. Documenting them once here keeps individual endpoint pages tight — endpoint blocks will point back at the relevant section instead of repeating the same tables.
Pagination
Every list endpoint (GET /api/<resource>/) uses cursor-based pagination with a consistent set of query parameters:
| Parameter | Type | Default | Notes |
|---|---|---|---|
cursor | string | — | Opaque token. Pass the next_cursor from the previous response to fetch the next page. Omit for the first page. |
limit | integer | 50 | Page size, 1–250. |
sort_by | string | varies | Any sortable field on the resource. See the resource's /filters endpoint for the list. Defaults are documented per endpoint. |
sort_order | string | desc | asc or desc. |
hydrate | boolean | true | When false, related objects are returned as IDs only (see Hydration). |
include_total | boolean | true | When false, the server skips counting collection_total — useful for very large lists. |
Response shape
List responses use a unified cursor-page envelope (the schema names follow the pattern <Resource>InDbCursorPage):
{
"items": [ /* page of results */ ],
"next_cursor": "eyJ…", // null on the last page
"next_page": true, // false on the last page
"limit": 50,
"collection_total": 1284 // 0 when include_total=false
}Walking all pages
let cursor = null
do {
const url = new URL('https://<tenant>.s-launch.com/api/store/asset/')
if (cursor) url.searchParams.set('cursor', cursor)
url.searchParams.set('limit', '100')
const page = await fetch(url, {
headers: { Authorization: `Bearer ${access_token}` },
}).then(r => r.json())
for (const item of page.items) handle(item)
cursor = page.next_page ? page.next_cursor : null
} while (cursor)Hydration
The hydrate query parameter (default true) controls whether the server expands related objects in the response. With hydrate=true, a record's foreign references include nested objects; with hydrate=false, they collapse to IDs.
Use hydrate=false when:
- You only need IDs (e.g., bulk-listing for a delete operation).
- You are paginating very large collections and want smaller payloads.
- You will fetch the related objects in a single follow-up call.
The payload shape changes — code that consumes the response should branch on the field type (object vs string) or pin hydrate to a fixed value.
Filter Metadata Endpoints
Every list endpoint has a sibling /filters endpoint that describes the filters, operators, and sortable fields supported by that list:
| Pattern | Example |
|---|---|
GET /api/<resource>/filters | GET /api/store/asset/filters |
These endpoints return an open object whose shape is intentionally flexible — the frontend uses it to render dynamic filter UIs. Inspect the live response for the resource you care about; the structure typically includes one entry per filterable field with allowed operators (eq, in, gt, lt, contains, etc.) and a list of sortable field names.
The required scope for /filters matches the scope for the parent list endpoint (e.g., store:read for asset filters).
Filtering
Apply filters by adding them as query parameters to a list endpoint. The accepted parameter names and operators are exactly what the matching /filters endpoint reports. Common patterns:
GET /api/store/asset/?name__contains=logo&created__gte=2026-01-01
GET /api/admin/users/?email__in=alice@x.com,bob@x.comThe exact syntax varies per field type — consult the /filters response for the canonical operator names.
Errors
The platform uses standard HTTP status codes. Validation failures (the most common error class) return an HTTPValidationError body:
{
"detail": [
{
"loc": ["body", "username"],
"msg": "field required",
"type": "value_error.missing"
}
]
}| Status | Meaning | Typical cause |
|---|---|---|
400 | Bad request | Malformed payload, conflicting parameters. |
401 | Unauthorized | Missing/expired access token or invalid API key. |
403 | Forbidden | Authenticated, but the caller's scope set does not include the required scope. |
404 | Not found | Resource ID does not exist (or the caller lacks read access on it). |
409 | Conflict | Uniqueness violation or state-conflict on update. |
422 | Unprocessable entity (validation) | Body shape violates HTTPValidationError — see detail. |
5xx | Server error | Treat as transient; retry with backoff. |
Endpoint pages list only the non-standard error codes they can return. Standard codes (401, 403, 422) apply across nearly every endpoint and are not repeated.
Headers
| Header | When to send |
|---|---|
Authorization | OAuth2 sessions. Format: Bearer <access_token>. |
X-API-Key | API-key authentication. Mutually exclusive with Authorization in practice. |
Content-Type | application/json for JSON bodies, application/x-www-form-urlencoded for OAuth2 login, multipart/form-data for uploads. |
Accept | Defaults to application/json. Set explicitly when consuming download endpoints that return binary content. |
IDs and Timestamps
- IDs are opaque strings. Do not assume any particular format (UUID, ObjectId, etc.) — they may change.
- Timestamps are ISO 8601 in UTC (e.g.,
2026-05-28T14:21:09.842Z). When filtering by date, the same format is accepted.
Uploads
Endpoints that accept binary data (e.g., asset uploads, avatar uploads, form file uploads) use multipart/form-data with the file in a file field. Each such endpoint documents the expected field name and any additional metadata fields it accepts.
Maximum upload size
Uploads are limited to 100 MB per request. A request whose body exceeds this is rejected with 413 Payload Too Large before it reaches the API, so nothing is stored. Need to move larger files? Contact your S-Launch representative.
See also
- Interactive Reference — full schema details for every list envelope and validation error.
- Authentication — how to obtain a token or API key.
- Scopes — the scope vocabulary referenced by
403errors.
