Skip to main content

Administration

This page is for key administrators. Administration still uses the /v1 endpoints, which remain available after the retirement of the v1 data APIs.

How permissions work​

TermMeaning
PrincipalA person or a system. It has a grant (the maximum it may hold) and optionally a usage policy
GrantThe maximum data scope, capabilities and licences of a principal
KeyBelongs to a principal and has its own data scope and capabilities, inside the principal's grant. One principal can have several keys, for example one personal and one for an agent
Effective permissionThe intersection of the key's scope and the principal's grant. A request that exceeds either is refused as a whole

An administrator can only manage principals and keys whose permissions lie inside their own, and cannot issue permissions larger than their own.

Data scope​

FieldTypeMeaning
kindsstring[]Data kinds, for example ["book_snapshot"]
referenceboolReference data
venues, all_venuesstring[], boolVenues, or all
instruments, all_instrumentsint[], boolInstrument ids, or all
time{start, end}Event-time range; omitted means no limit
historyboolHistory reads and exports
liveboolLive subscriptions
book_depth, all_book_depthint, boolBook levels, or all
exportboolCreate exports

venues and instruments are stored but are not yet applied to /v2 requests; use kinds, history, live, export and book depth to control access today.

Capabilities​

CapabilityAllows
admin.principalsCreate principals and change their grants and policies
admin.keysIssue, list, show, revoke and rotate keys; change a key's scope and expiry
admin.quotaCreate and change usage policies; assign one to a principal
admin.dataData management, derivations and live-bar jobs
admin.referenceReference data and bar specifications

Give administration capabilities only to administrators. A normal user's grant has none.

Create a user​

ADMIN='vmk_...'
API=https://data.cyberun.cloud
H=(-H "Authorization: Bearer $ADMIN" -H "Content-Type: application/json")

# 1. Optional: a usage policy shared by several principals
curl -s "${H[@]}" $API/v2/admin/quota/policies -d '{
"name": "trader", "requests_per_min": 600, "output_bytes_per_min": 536870912,
"jobs_per_hour": 20, "concurrency": 4,
"subscriptions": 4, "event_bytes_per_min": 16777216, "scanned_bytes_per_min": 1073741824}'
# -> {"id": "<policy-id>"}

# 2. Principal: grant is the ceiling; normal users get no capabilities
curl -s "${H[@]}" $API/v2/admin/principals -d '{
"name": "trader-alice",
"grant": {"data": {"kinds": ["book_snapshot"], "reference": true,
"all_venues": true, "all_instruments": true,
"history": true, "live": true, "export": true,
"all_book_depth": true},
"caps": []},
"policy": "<policy-id>"}'
# -> {"id": "<principal-id>"}

# 3. Key: the secret appears only in this answer
curl -s "${H[@]}" $API/v2/admin/keys -d '{
"owner": "<principal-id>",
"scope": {"data": {"kinds": ["book_snapshot"], "reference": true,
"all_venues": true, "all_instruments": true,
"history": true, "live": true, "export": true,
"all_book_depth": true},
"caps": []},
"expires_in": "2160h"}'
# -> {"key": "vmk_...", "record": {"id": "...", "principal": "...",
# "created": "...", "expires": "..."}}

For an agent, issue a second key to the same principal with a narrower scope, for example without live and export.

v2 permissions​

FeatureGrant and key scope need
/v2/catalog/*, /v2/schemasAny valid key
/v2/data, /v2/barsbook_snapshot (or bar for bars), history, and a book depth for snapshots
/v2/exportsThe snapshot permissions plus export
/v2/streambook_snapshot, live, and a book depth

With veinmeshctl, change grants and key scopes by flag instead of rewriting the whole JSON:

veinmeshctl principal grant <principal> --add-kinds book_snapshot --history --live --export --book-depth all
veinmeshctl key scope <key-id> --add-kinds book_snapshot --history --live --export --book-depth all

The CLI refuses to grant more than the caller holds and says which part was too large.

Endpoints​

Principals​

Method and pathBodyAnswerCapability
POST /v2/admin/principals{"name", "grant", "policy"?}{"id"}admin.principals
GET /v2/admin/principals{"principals": [...]}, only within the caller's permissionsadmin.principals
GET /v2/admin/principals/{id}The principal with its grantadmin.principals
PUT /v2/admin/principals/{id}/grant{"grant": {...}}204admin.principals
PUT /v2/admin/principals/{id}/policy{"policy": "<id>"}; empty removes it204admin.quota

Reducing a grant immediately limits every key of that principal.

Keys​

Method and pathBodyAnswer
POST /v2/admin/keys{"owner", "scope": {"data": ..., "caps": []}, "expires_in"?}{"key", "record"}
GET /v2/admin/keys?owner=<principal-id>{"keys": [...]} without secrets
GET /v2/admin/keys/{id}One record with its scope
GET /v2/whoamiThe caller's key, principal and effective permissions
POST /v2/admin/keys/{id}/revoke204
POST /v2/admin/keys/{id}/rotate{"overlap"?: "24h"}{"key", "record"}
PUT /v2/admin/keys/{id}/scope{"scope": {...}}204
PUT /v2/admin/keys/{id}/expiry{"expires": "2027-01-01T00:00:00Z"}204

All except whoami need admin.keys.

  • expires_in is hours, for example 2160h. Default and maximum lifetimes are in Limits.
  • overlap defaults to 0 (the old key expires immediately) and is at most 24 hours. The old key never outlives its original expiry.
  • Revocation takes effect within about a minute; live connections are told and closed.
  • The key id is the <id> in vmk_<id>_<secret>; the secret is never shown again.

Usage policies​

POST /v2/admin/quota/policies with admin.quota: without id it creates a policy, with id it changes one; the answer is {"id"}.

FieldMeaningDefault
nameNamerequired
requests_per_minRequests per minute (HTTP, MCP calls and WebSocket connections)required; 0 = unlimited
output_bytes_per_minResponse bytes per minuterequired; 0 = unlimited
jobs_per_hourJobs per hour, for example computationsrequired; 0 = unlimited
concurrencyConcurrent requestsrequired; 0 = unlimited
subscriptionsConcurrent WebSocket subscriptions4; 0 = unlimited
event_bytes_per_minWebSocket bytes per minute16 MiB; 0 = unlimited
scanned_bytes_per_minBytes read by queries per minute1 GiB on create; unchanged when omitted on update; 0 = unlimited
warning

A principal without a policy has no usage limit. Policies currently govern the v1 endpoints; /v2 does not yet enforce them. Assign one anyway so the account behaves correctly when v2 enforcement arrives.

Over a limit answers quota_exceeded (429) with reset_after; a single request larger than the limit answers resource_exhausted (413).