APIs

APIs

Choose between the hosted control-plane API and the engine data-plane API.


rstream exposes two HTTP surfaces. The hosted control plane lives under https://rstream.io/api/... and covers managed project discovery, hosted platform operations, and TURN issuance. The engine data plane lives under https://<engine>/api/... and covers operational state inside a specific tunnels project.

Most integrations are better served by an SDK than by raw HTTP. The SDKs already handle project resolution, application credentials, short-lived tokens, and the split between hosted and self-hosted deployments. This page is intended for the smaller set of cases where raw HTTP remains useful, such as lightweight automation, custom runtimes without an SDK, or direct inspection of the wire-level API.

Choosing the right surface

The hosted control plane is the right surface for whoami, project listing, project-endpoint resolution, managed TURN issuance, and other operations that exist only in the managed platform. The engine API is the right surface for listing tunnels and clients, subscribing to state.initial, client.*, and tunnel.* events, and working against self-hosted deployments where no hosted control plane exists.

In hosted deployments, the common path is to call the control plane first to discover or resolve the project, then call the engine for operational work. In self-hosted deployments, the engine is often the only HTTP surface available.

Hosted control-plane API

The hosted control plane is the API behind project discovery and other managed platform operations. Not every dashboard route should be treated as a stable public contract, which is why the recommended entrypoint is usually the JS SDK or the Go SDK. The operational routes that matter most are shown below.

The machine-readable OpenAPI contract is published at /api/openapi.json and advertised from /.well-known/api-catalog.

GET  /api/whoami
GET  /api/projects/tunnels
GET  /api/workspaces/<workspace-id>/projects/tunnels/plan/config
POST /api/workspaces/<workspace-id>/projects/tunnels/payment-checkout
POST /api/workspaces/<workspace-id>/projects/tunnels/payment-checkout/complete
POST /api/workspaces/<workspace-id>/projects/tunnels/payment-checkout/cancel
POST /api/workspaces/<workspace-id>/projects/tunnels
GET  /api/projects/tunnels/resolve/<project-endpoint>
POST /api/projects/tunnels/<project-id>/turn-server/credentials
POST /api/projects/tunnels/resolve/<project-endpoint>/turn-server/credentials

This layer is the part of the platform that knows about workspaces, managed projects, hosted plan state, and platform-issued TURN credentials.

Project creation is intentionally a preview-confirm flow. First, call the plan configuration endpoint for the workspace. It returns available and unavailable plans, provider/region choices, a recommended region when geolocation is available, billingImpact, billingAction, and a creationFingerprint.

The server selects the creation action through billingAction; browsers and agents should not choose a billing mode themselves. When billingAction.type is stripe_checkout, call the payment checkout endpoint with the same selected plan, provider, region, creationFingerprint, and idempotencyKey, then send the user to the returned Stripe URL. Stripe confirms the immediate charge and recurring workspace billing in one flow. On success, call the checkout completion endpoint with the returned checkout_session_id; it finalizes the reserved project and returns the project to open. On cancel, call the checkout cancel endpoint with the returned project_id; it removes the reserved project so the same name can be retried.

When billingAction.type is none or confirm_create, call the project creation endpoint. Always pass the selected plan, provider, region, the selected creationFingerprint, and an idempotencyKey. If the response is 409, the preview no longer matches current billing, allowed billing modes, or capacity state; refresh the plan configuration and ask the user to confirm the updated billing impact before retrying.

Stripe Checkout is not used to add another project to an existing workspace subscription. Existing subscriptions are updated server-side after the user has confirmed the returned billing impact. If the environment disables server-confirmed creation, plans that would require updating an existing subscription are reported as unavailable.

Engine API

The engine exposes four operational endpoints under /api: /api/clients, /api/tunnels, /api/sse, and /api/websocket. The list endpoints answer point-in-time inventory queries, while the signaling endpoints send a filtered initial snapshot followed by incremental updates.

In hosted mode, the engine remains scoped to a single project. In self-hosted mode, this may be the only HTTP API surface present.

The machine-readable engine OpenAPI contract is published by the website at /api/engine/openapi.json and by the engine itself at /api/openapi.json when that engine build includes discovery. The API catalog advertises the website copy so agents can discover the data-plane schema before they know a project-specific engine host.

Authentication

Engine list and signaling endpoints accept bearer authentication either through Authorization: Bearer <token> or through the rstream.token=<token> query parameter when a header is not practical. Hosted control-plane routes use standard bearer authentication through Authorization.

For backend code, SDK-managed authentication remains the preferred path, especially when application credentials, fine-grained tokens, project-endpoint resolution, or managed TURN issuance are involved.

Agent automation permissions

Agents that operate tunnels usually need permissions on both surfaces. Hosted control-plane permissions let the agent discover or manage projects. Engine permissions let the agent create tunnels, dial private tunnels, and inspect live runtime state.

OpenAPI operations expose backend checks through x-rstream-required-rules. The same OpenAPI document exposes x-rstream-permissions, a dictionary mapping each OAuth permission to the rules it grants, and x-rstream-use-case-permissions, a small set of practical bundles for common agent workflows. Agents should use the bundles for normal product tasks and fall back to the rule dictionary when planning a custom workflow.

Common hosted control-plane permissions:

TaskPermission
List, select, or resolve tunnel projectsaccount.projects.read-only
Read project creation optionsaccount.plan.read-only
Create, update, transfer, or delete tunnel projectsaccount.projects.read-write
Read hosted request and connection logsnetwork.streams.read-only
Read hosted project plan, usage, or TURN usageaccount.plan.read-only
Create managed TURN credentialsnetwork.turn-server-credentials.create
Mint short-lived delegated tokensaccount.tokens.create
Manage long-lived credentialsaccount.credentials.read-write

Common engine data-plane permissions:

TaskPermission
Read active clients, active tunnels, and live eventstunnels.resources.read-only
Create or close tunnels through the CLI, SDK, or enginetunnels.tunnels.create-delete
Dial private tunnels or open and close tunnel streamstunnels.streams.create-delete

For an agent that must create or select a hosted project, open a local tunnel, follow live state, and read hosted logs, a practical OAuth scope request is:

account.projects.read-write account.projects.read-only account.plan.read-only network.streams.read-only tunnels.resources.read-only tunnels.tunnels.create-delete tunnels.streams.create-delete

For an agent that only needs to use an existing project and open a tunnel next to a local service, prefer:

account.projects.read-only tunnels.resources.read-only tunnels.tunnels.create-delete

For an agent that only connects to private tunnels, prefer:

account.projects.read-only tunnels.resources.read-only tunnels.streams.create-delete

Only request token or credential-management permissions when the user explicitly asks the agent to issue, rotate, revoke, or manage credentials. For tighter delegation inside one project, combine permissions with tunnel grants documented in Fine-Grained Tokens.

Engine list parameters

/api/clients and /api/tunnels accept an optional params query parameter encoded as JSON. On both endpoints, limit restricts the number of returned objects and filters narrows the result set. These calls are already scoped to the authenticated project, so filters focus on the resources inside that project rather than on workspace or project metadata.

Tunnel filters are typically built around labels, publish state, protocol, HTTP version, ownership, client attachment, or tunnel name:

curl -G "https://<engine>/api/tunnels" \
  -H "Authorization: Bearer <token>" \
  --data-urlencode 'params={"filters":{"name":"ssh-prod-01","labels":{"service":"ssh","env":"prod"}}}'

Client filters are usually built around agent metadata such as agent, channel, version, os, arch, labels, or user_id:

curl -G "https://<engine>/api/clients" \
  -H "Authorization: Bearer <token>" \
  --data-urlencode 'params={"filters":{"agent":"rstream","channel":"dev"}}'

Labels are usually the most stable tunnel selector in practice. See Labels for the broader model.

Engine signaling parameters

/api/sse and /api/websocket accept the same params query parameter, but the structure separates client filters from tunnel filters:

curl -N -G "https://<engine>/api/sse" \
  --data-urlencode 'rstream.token=<token>' \
  --data-urlencode 'params={"clients":{"agent":"rstream"},"tunnels":{"labels":{"service":"ssh","env":"prod"}}}'

The same params value can be used on /api/websocket. In both transports, the initial state.initial event is filtered before it is sent, and subsequent client.* and tunnel.* events are filtered with the same rules. This is the same model exposed by the CLI and SDK watch helpers. For more detail, see Signaling.

TURN issuance

TURN credential issuance belongs to the hosted control plane, not to the engine list or signaling API. The raw hosted routes are POST /api/projects/tunnels/<project-id>/turn-server/credentials and POST /api/projects/tunnels/resolve/<project-endpoint>/turn-server/credentials. For production code, the SDK helpers documented in STUN and TURN remain the preferred entrypoint.

When raw HTTP is the right choice

Raw HTTP is most useful from runtimes where no rstream SDK exists yet, for very small operational probes, or for direct inspection of list and signaling behavior. The SDKs are the better fit when project resolution, application credentials, short-lived or fine-grained tokens, TURN issuance, or one abstraction across hosted and self-hosted modes is required.

For the higher-level surfaces built on top of these routes, see JS SDK, Go SDK, Signaling, Labels, and STUN and TURN.