Skip to content

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:

ParameterTypeDefaultNotes
cursorstringOpaque token. Pass the next_cursor from the previous response to fetch the next page. Omit for the first page.
limitinteger50Page size, 1–250.
sort_bystringvariesAny sortable field on the resource. See the resource's /filters endpoint for the list. Defaults are documented per endpoint.
sort_orderstringdescasc or desc.
hydratebooleantrueWhen false, related objects are returned as IDs only (see Hydration).
include_totalbooleantrueWhen 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):

json
{
  "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

js
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:

PatternExample
GET /api/<resource>/filtersGET /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.com

The 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:

json
{
  "detail": [
    {
      "loc": ["body", "username"],
      "msg": "field required",
      "type": "value_error.missing"
    }
  ]
}
StatusMeaningTypical cause
400Bad requestMalformed payload, conflicting parameters.
401UnauthorizedMissing/expired access token or invalid API key.
403ForbiddenAuthenticated, but the caller's scope set does not include the required scope.
404Not foundResource ID does not exist (or the caller lacks read access on it).
409ConflictUniqueness violation or state-conflict on update.
422Unprocessable entity (validation)Body shape violates HTTPValidationError — see detail.
5xxServer errorTreat 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

HeaderWhen to send
AuthorizationOAuth2 sessions. Format: Bearer <access_token>.
X-API-KeyAPI-key authentication. Mutually exclusive with Authorization in practice.
Content-Typeapplication/json for JSON bodies, application/x-www-form-urlencoded for OAuth2 login, multipart/form-data for uploads.
AcceptDefaults 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

S-Launch