Skip to main content

Conventions

Read these once. They apply to every endpoint in the generated reference.

Response envelope

Every non-auth, non-webhook endpoint returns:

{
"requestId": "550e8400-e29b-41d4-a716-446655440000",
"timestamp": "2026-05-14T12:00:00.000Z",
"status": "success",
"statusCode": 200,
"data": { /* payload */ },
"error": null
}

On error:

{
"requestId": "550e8400-...",
"timestamp": "2026-05-14T12:00:00.000Z",
"status": "error",
"statusCode": 403,
"data": null,
"error": {
"code": "FORBIDDEN",
"message": "Only platform admins can access this resource",
"details": {}
}
}

For paginated reads, an extra pagination field:

{
"status": "success",
"data": [/* ... */],
"pagination": { "cursor": "abc123", "hasMore": true, "limit": 20 },
"error": null
}

Exceptions to the envelope

EndpointWhy bare response
/api/auth/* (better-auth)Spec'd by OIDC/OAuth, has its own format
/api/auth/oauth2/*OAuth 2.0 spec
/webhooks/stripeBare 200/4xx body, headers carry signature
File uploads (multipart response)Returns { url } directly inside the envelope

The ApiResponseInterceptor detects res.headersSent and skips wrapping. So if a controller calls res.send() directly, no envelope.

Path naming

PatternMeaning
/agents/:agentId/...Resource is scoped to an agent. Path params validated by an agent existence check.
/me/...Resource is scoped to the current user. Requires auth.
/admin/...Requires platform_admin role.
/api/auth/...better-auth namespace.
/webhooks/...Inbound webhooks.
/healthLiveness only. No envelope.

HTTP method semantics

  • GET — never mutates.
  • POST on :id path — partial or full update (legacy from Express conventions; should be PATCH but isn't).
  • POST on collection — create.
  • PUT — used for idempotent upserts (e.g. tier quotas).
  • DELETE — soft delete where possible.

Identifiers

IdentifierFormat
Most IDsUUID v4 (8d1...)
SlugsKebab-case (ai-support)
Stripe IDsprod_*, price_*, sub_*, cus_*, cs_*
Tags[a-z0-9-]+

Timestamps

ISO 8601 UTC with milliseconds: 2026-05-14T12:00:00.000Z. Always.

Currencies

Lowercase ISO 4217 (usd, inr, eur). Stripe uses minor units (cents) internally; the marketplace API surfaces decimal strings ("49.00") for clarity.

Request IDs

Every response has requestId (UUID). Echo it when filing bug reports — it correlates to PostHog audit log rows.

Rate limiting

Not currently enforced at the framework level. Stripe webhook idempotency provides natural deduplication; quota consume calls deduplicate via clientReqId.

Versioning

No URL version prefix. Breaking changes will be communicated via Changelog / Release notes and (eventually) x-api-version response header.