Control API

Introduction

The Control API manages Capacity budgets, the sources on them, access keys, webhook destinations, and source Metrics from your tools. It lives on your swarmvia host (for example https://swarmvia.com), not on api.swarmvia.cloud.

The API token is not an access key. It never admits traffic on the proxy.

It is also not how AI assistants connect. Those use the MCP server at https://swarmvia.com/mcp. See Agents for how to add that URL in Claude or Cursor. There is no token to paste. Use an API token for CI, scripts, and infrastructure code, where a value in an environment variable is the right shape.

Authentication

  1. Open Organization settings → API tokens.
  2. Create a token. Choose when it expires: 1 month, 6 months, or 1 year.
  3. Copy the plain token once. Send it as Authorization: Bearer ….

A token looks like 12|sv_api_…: its id, a |, and the secret. Send the whole value. Tokens created before the sv_api_ prefix have no prefix after the |, and they keep working.

Only owners and admins can create or revoke tokens. A token authenticates as the person who created it in that organization. It can call the Control API for every budget and source on the org. Verb abilities still apply (budgets:read, sources:read, sources:write, keys:write, metrics:read). Webhook create and attach use sources:write. Listing destinations uses sources:read.

curl -sS "https://swarmvia.com/api/v1/me" \
  -H "Authorization: Bearer $NTHBOUNCER_CONTROL_TOKEN" \
  -H "Accept: application/json"

Endpoints

Source path segments use the source subdomain (the *.swarmvia.cloud label).

Method Path Ability Purpose
GET /api/v1/me (any valid token) Current user, team, abilities
GET /api/v1/budgets budgets:read List granted budgets
GET /api/v1/budgets/{id} budgets:read Budget detail
GET /api/v1/budgets/{id}/sources sources:read Sources under that budget
GET /api/v1/sources sources:read List granted sources
POST /api/v1/sources sources:write Admit an https origin (same as MCP create_source)
POST /api/v1/sources/database sources:write Admit a public Postgres host
POST /api/v1/sources/{subdomain}/auth-handoff sources:write Flip to managed auth and mint a one-shot intake
PUT /api/v1/sources/{subdomain}/credential sources:write Attach a stored credential (secret allowed on this plane)
GET /api/v1/sources/{subdomain} sources:read Source detail
POST /api/v1/sources/{subdomain}/keys keys:write Mint an access key (sv_at_…, expires in 1h, 24h, or 7d)
DELETE /api/v1/sources/{subdomain}/keys/{id} keys:write Revoke an access key
GET /api/v1/sources/{subdomain}/metrics metrics:read Admit / queue / reject series
GET /api/v1/webhooks sources:read List webhook destinations
POST /api/v1/webhooks sources:write Create a destination (signing secret once). Optional source_ids attaches and enables async
PUT /api/v1/sources/{subdomain}/webhooks sources:write Replace destinations on a source. Enables async when the list is not empty

POST /api/v1/sources takes origin (required) and name (optional). It reuses a live API source that already fronts that host, or creates a pass-through source with dashboard defaults. It does not attach a Capacity budget or an origin credential. 201 on create, 200 on reuse.

Attach budgets and managed credentials in the dashboard.

POST /api/v1/webhooks takes name, url, optional description, and optional source_ids. The URL must be https and cannot be loopback, private, or swarmvia itself. 201 returns signing_secret once (whsec_…).

PUT /api/v1/sources/{subdomain}/webhooks takes webhook_endpoint_ids (may be empty). Owners and admins only, same as the dashboard.

Mint an access key

curl -sS -X POST "https://swarmvia.com/api/v1/sources/$SOURCE_SUBDOMAIN/keys" \
  -H "Authorization: Bearer $NTHBOUNCER_CONTROL_TOKEN" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{"label":"orders-sync","expires_preset":"24h"}'

The body is optional:

Field Values Default
label Up to 60 characters. Names the key on the Access tab, in Logs, and in Metrics. none
access read or write (see Key access) write
expires_preset 1h, 24h, or 7d 24h
for_me true signs the key for the user who owns the Control API token, so it acts for them false

Every key expires; 7 days is the longest. expires_preset: "none" is refused with 422. Without for_me, a minted key is a machine key: it acts for no one. A source whose credential is per member needs for_me: true.

201 returns the key once, in data.key, with its expires_at:

{
  "data": {
    "id": 4821,
    "label": "orders-sync",
    "last_four": "Q2xk",
    "access": "write",
    "allowed_methods": null,
    "expires_at": "2026-10-19T14:05:00+00:00",
    "revoked_at": null,
    "created_at": "2026-10-18T14:05:00+00:00",
    "key": "sv_at_eyJhbGciOiJFZERTQSIs…"
  }
}

Cache the key and mint a new one once about 80% of its lifetime has passed. Refresh access tokens before they expire shows the pattern, including tools that can only send a fixed header.

Revoke an access key

DELETE /api/v1/sources/{subdomain}/keys/{id} revokes the key with that id at once and returns it with revoked_at set. Revoke a key only if it leaked; otherwise let it expire.

Key access

POST /api/v1/sources/{subdomain}/keys accepts access:

Value Methods admitted
write (default) Every method
read GET, HEAD, OPTIONS, plus any methods the source treats as reads

A read-only key is refused with 403 on any other method, before the request reaches your origin and before it takes a concurrency slot. The response includes access and allowed_methods so a caller can check what it holds (allowed_methods is null on a write key, which admits every method). When the source scopes extra read methods to path prefixes, the response also includes read_paths, keyed by method ({ "POST": ["/services/rest/query/"] }).

Omitting access mints a write key.

On a database source, access: read and access: write both connect as the read role. Method scope is not applied: every query is POST. Writes are refused by Postgres, not by the key.

MCP

AI assistants use https://swarmvia.com/mcp, not this token. Connection steps are on Agents. Tools and session keys are on MCP server.

Related