HTTP conventions
Generated routes follow one grammar, so clients can call any domain without per-domain code. All
paths sit under api_base (default /api).
Route grammar
| Kind | Method | Path |
|---|---|---|
| Collection command | POST | /{api_base}/{ns}/{cmdkey}:post/{resource} |
| Collection command, scoped | POST | /{api_base}/{ns}/{cmdkey}:post/{scope}/{resource} |
| Object command | POST | /{api_base}/{ns}/{cmdkey}:exec/{resource}/{id} |
| Object command, scoped | POST | /{api_base}/{ns}/{cmdkey}:exec/{scope}/{resource}/{id} |
| Signed link | GET | /{api_base}/{ns}/{cmdkey}:link/{link_token} |
| Signed hook | GET | /{api_base}/{ns}/{cmdkey}:hook/{hook_token} |
| Command metadata | GET | /{api_base}/{ns}/{cmdkey}.meta |
| Domain discovery | GET | /{api_base}/{ns}/domain.meta |
| List | GET | /{api_base}/{ns}/{resource}.list (scoped: .list/{scope}) |
| Item | GET | /{api_base}/{ns}/{resource}.item/{id} (scoped: .item/{scope}/{id}) |
| Resource metadata | GET | /{api_base}/{ns}/{resource}.meta |
| Report | POST | /{api_base}/{ns}/{report}.rept (scoped: .rept/{scope}) |
| OpenAPI | GET | /{api_base}/openapi.json |
Naming rules: namespaces are dotted (riverbase.todo), command keys are verb-noun with dashes
(create-todo), and resources are lowercase (todo, todo_summary). The method marker is joined
to the last segment (todo.list, create-todo:post), not a separate path segment.
Request bodies
Commands and reports take a JSON body with a single payload key:
{ "payload": { "title": "Buy milk" } }
With deny_unknown_fields = true, properties the payload type does not declare are rejected.
Responses
| Route | Body |
|---|---|
| Command | The handler's JSON result |
.list | { "data": [...], "pagination": { "limit", "offset", "page", "total", "pages" } } |
.item | The row object |
.meta | The interface descriptor: fields, field.operator filters, params, composites |
| Error | RFC 7807 problem JSON with errcode, errdata, and errhint; see Errors |
pagination.total is -1 when counting is skipped (count=false) or capped by query_count_max_rows.
Query parameters
limit, page, sort, include, exclude, query, qbase, text, count. See
Queries: the wire format.
Scopes
A scope is a path segment, not a query parameter. It narrows a command or query to a sub-context
such as a project or a workspace, and it is decoded into a JSON object that policy and handlers can
read. A command declares scope: required in its meta; a query resource declares it in
meta { scope: … }.
Signed links and hooks
| Kind | Enable with | Token config | Use |
|---|---|---|---|
:link | link: true in command meta | [riverbase.link_token]: RIVERBASE_LINK_TOKEN_SECRET, RIVERBASE_LINK_TOKEN_SALT | One-click links in email, such as "confirm subscription" |
:hook | hook: true in command meta | [riverbase.hook_token]: RIVERBASE_HOOK_TOKEN_SECRET, RIVERBASE_HOOK_TOKEN_SALT | JWT-signed trigger URLs for third-party webhooks |
The token carries the command arguments, so a plain GET can run the command safely.
Headers
| Header | Direction | Meaning |
|---|---|---|
Authorization | in | Bearer <JWT>, or MockAuth-… in development |
X-Profile | in | Pin the active profile for this request |
| Idempotency key header | in and out | Replay-safe retries; the response header name is set by resp_header_idempotency |
| Correlation id | out | Echoed for tracing across services |
API zones
Routes can be restricted to deployment zones. With api_zone = ["admin"], only routes allowed in
admin are registered, and only they appear in OpenAPI. Use zones to serve a public API and an
admin API from the same code in two deployments.