Vellarin Hub API reference

Vellarin Hub gives your own agent (Claude Code, Cursor, Codex, or anything that speaks MCP or HTTP) the apps your workspace connected in Vellarin Agents. One URL, one key. Reads run at once. Anything that writes waits for the workspace owner's approval and then runs exactly once. Every call is recorded and counted against hard caps.

MCP endpointhttps://hub.vellarin.ai/api/hub/mcp (Streamable HTTP, JSON responses)
REST basehttps://hub.vellarin.ai/api/hub/v1
AuthAuthorization: Bearer vhub_…

Authentication

Create an agent key on the Developers page of your workspace (owner or editor). The key looks like vhub_1a2b3c4d_… and is shown once: we store only a hash and the first eight characters. Send it on every request:

Authorization: Bearer vhub_1a2b3c4d_…
  • One key per agent. Give each key a name you will recognise on an approval request.
  • A key can be limited to some of the connected apps, and can have its own cap per day and per month.
  • Revoking a key stops it on the next request and rejects whatever it left waiting for approval.
  • The key is a secret. Keep it in an environment variable, not in a repository.

Connect a client

Claude Code · Terminal

claude mcp add --transport http vellarin https://hub.vellarin.ai/api/hub/mcp --header "Authorization: Bearer <key>"

Syntax checked against code.claude.com/docs/en/mcp

Cursor · ~/.cursor/mcp.json (or .cursor/mcp.json in a project)

{
  "mcpServers": {
    "vellarin": {
      "url": "https://hub.vellarin.ai/api/hub/mcp",
      "headers": {
        "Authorization": "Bearer ${env:VELLARIN_HUB_KEY}"
      }
    }
  }
}

Syntax checked against cursor.com/docs/context/mcp

Codex · ~/.codex/config.toml

[mcp_servers.vellarin]
url = "https://hub.vellarin.ai/api/hub/mcp"
bearer_token_env_var = "VELLARIN_HUB_KEY"

Syntax checked against developers.openai.com/codex/mcp

curl · REST

curl https://hub.vellarin.ai/api/hub/v1/tools \
  -H "Authorization: Bearer <key>"

curl -X POST https://hub.vellarin.ai/api/hub/v1/tools/<tool_name>/call \
  -H "Authorization: Bearer <key>" \
  -H "Content-Type: application/json" \
  -d '{"arguments": {}}'

Cursor and Codex read the key from an environment variable: export VELLARIN_HUB_KEY="<key>"

MCP endpoint

POST https://hub.vellarin.ai/api/hub/mcp with a JSON-RPC 2.0 message. Supported methods: initialize, ping, tools/list, tools/call. Responses are plain JSON (no SSE stream, no session id, no batches). Notifications answer 202.

tools/list

Returns the actions of the connected apps this key may use (up to 150, taken in turns from each app), plus find_app_actions when there are more, plus vellarin_approval_status. Read actions carry annotations.readOnlyHint: true. Listing is free.

curl https://hub.vellarin.ai/api/hub/mcp \
  -H "Authorization: Bearer <key>" -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'

tools/call

{"jsonrpc":"2.0","id":2,"method":"tools/call",
 "params":{"name":"<tool_name>","arguments":{}}}

The result is a normal MCP tool result (content[0].text, isError) with two extra fields in _meta: vellarin/status (ok, waiting_approval, rejected, error, rate_limited) and, for writes, vellarin/approvalId.

Approvals

A write action never runs on the first call. The flow is the same over MCP and REST:

  • Call the action. The answer comes back at once: status waiting_approval and an approval id. Nothing was sent.
  • The owner decides. The request shows on the Developers page and the team home, labelled "From your own agent: <key name>", and the owner gets an email.
  • Check. Call the tool vellarin_approval_status with {"approval_id": "…"}, or GET /v1/approvals/{id}. It answers pending, approved or rejected.
  • Run it. Once approved, call the same action with the same arguments. It runs once. Calling it again later asks for a new approval.

The approval is tied to the key, the action and the exact arguments (key order does not matter). Changing an argument is a different request. A key can have up to 20 requests waiting at a time.

REST API

RequestWhat it doesAnswers
GET /v1/toolsThe actions this key may call: name, description, inputSchema, readOnly.200
POST /v1/tools/{name}/callRuns one action. Body {"arguments": {…}}. Add ?wait=20 to keep the request open up to 20 seconds for the owner's answer.200 ok · 202 waiting_approval · 409 rejected · 422 the app answered with an error · 429
GET /v1/approvals/{id}Status of an approval this key asked for: status, reason, label, createdAt, decidedAt.200 · 404
GET /v1/usageCalls used this month against the plan, and this key's own day and month counts and caps.200
curl https://hub.vellarin.ai/api/hub/v1/tools \
  -H "Authorization: Bearer <key>"

curl -X POST https://hub.vellarin.ai/api/hub/v1/tools/<tool_name>/call \
  -H "Authorization: Bearer <key>" \
  -H "Content-Type: application/json" \
  -d '{"arguments": {}}'

A call answers {"status": "ok", "approvalId": null, "result": "…"}. result is the app's answer as text (JSON when the app returns JSON), cut at 60,000 characters.

Shared memory

A key-value store for the workspace, reached with the same key. Use it for state that should outlive a run: the last processed id, a customer's preferences, a summary another agent will pick up. Every key of the workspace reads and writes the same store; use prefixes (customer:42) to keep things apart.

RESTMCP toolWhat it does
PUT /v1/memory/{key}vellarin_memory_setSaves {"value": "…", "ttl_seconds": 3600}. ttl_seconds is optional (60 or more).
GET /v1/memory/{key}vellarin_memory_getAnswers key, value, updatedAt, expiresAt, or 404.
GET /v1/memory?prefix=vellarin_memory_listThe keys (up to 200), without values.
DELETE /v1/memory/{key}vellarin_memory_deleteRemoves the key.
curl -X PUT https://hub.vellarin.ai/api/hub/v1/memory/customer:42 \
  -H "Authorization: Bearer <key>" -H "Content-Type: application/json" \
  -d '{"value": "{\"tier\": \"gold\"}"}'
  • Keys: 1 to 200 characters, letters, digits and . : - _. Values: text up to 16,000 characters (send JSON as text).
  • Hub Free: 100 keys. Hub Team: 5,000 keys. Updating an existing key is always allowed.
  • Memory is not a secrets store: the workspace owner can read it. Keep API keys and passwords elsewhere.

Run log

Your agent writes what it did, and Hub adds it up per run: steps, tokens in and out, cost, time and errors. The latest runs show on the Developers page. Events with the same run belong together.

RESTMCP toolWhat it does
POST /v1/tracesvellarin_trace_logOne event, or {"events": [...]} with up to 100.
GET /v1/runsThe latest runs with events, errors, inputTokens, outputTokens, costUsd, ms, models.
GET /v1/traces?run=The events of one run, in order, with its totals.
curl -X POST https://hub.vellarin.ai/api/hub/v1/traces \
  -H "Authorization: Bearer <key>" -H "Content-Type: application/json" \
  -d '{"events": [
    {"run": "weekly-report-1", "name": "draft summary", "kind": "llm", "model": "your-model",
     "input_tokens": 4120, "output_tokens": 630, "cost_usd": 0.021, "ms": 4800},
    {"run": "weekly-report-1", "name": "send email", "kind": "tool", "ms": 310}
  ]}'
  • An event has run and name, a kind (llm, tool, step, error) and optionally model, input_tokens, output_tokens, cost_usd, ms, status and a note of up to 500 characters.
  • Hub stores what your agent reports; it does not see your model calls. Do not put secrets or personal data in note.
  • Hub Free: 5,000 events a month. Hub Team: 100,000. Kept 30 days.

Eval results

A place to record eval results from your agent or your CI, and to read how each suite is doing. Hub stores results; it does not run the evals.

RESTMCP toolWhat it does
POST /v1/evalsvellarin_eval_recordOne result, or {"results": [...]} with up to 100: suite, case, and score (0 to 1), pass, or both; optional run and note.
GET /v1/evals?suite=Per suite: results, passRate, avgScore, lastRun and lastRunPassRate.
  • With only score, a result passes at 0.5 or more. With only pass, the score is 1 or 0.
  • Hub Free: 1,000 results a month. Hub Team: 50,000. Kept 30 days.

Errors

REST errors are {"error": "<code>", "message": "<plain sentence>"}. MCP errors are JSON-RPC errors with the same HTTP status, the sentence in error.message and the code in error.data.error.

HTTPCodeMeaning
401unauthorizedThe key is missing, malformed, unknown or revoked. One answer for all four.
402payment_requiredThe last payment of the workspace's Hub plan did not go through. The owner updates the card on the Developers page.
403workspace_paused · workspace_suspended · forbidden_originThe workspace is paused or not active, or the request came from a web page (call it from your agent or server).
413too_largeThe request body is larger than 256 KB.
429cap_reachedA cap was reached. The body says which one (scope: key_day, key_month or workspace_month), the limit, the count and resetsAt; the Retry-After header carries the seconds. Upgrade or wait.
503unavailableHub cannot count or reach what it needs right now. Nothing ran. Try again in a moment.

Limits

PlanAgent keysCalls per monthPrice
Hub Free1500USD 0
Hub Team105,000USD 19 a month, or USD 180 a year (USD 15 a month)
  • A call counts when it reached the app: a read that worked, or an approved write that ran. Listing tools, checking an approval, a call waiting for approval and a failed read are free.
  • The month is the calendar month in UTC; a key's daily cap resets at 00:00 UTC.
  • Memory, the run log and eval results have their own allowances (above), are limited to 120 requests a minute per key, and never count as calls.
  • 60 calls a minute per key and 300 per workspace. Over that, the call answers rate_limited.
  • Over the cap the answer is 429 "upgrade or wait". There is no wallet, no top-up and no overage charge.

Security

  • Your agent never holds an app credential. Sign-ins live with the apps provider on the server side; your agent holds only the Vellarin key.
  • Approval requests show the app, the action and its first target (a recipient, a channel). Message bodies are not stored in the request or in the call record.
  • The call record keeps the app, the action, read or write, the outcome and the time. It keeps no arguments and no results.
  • What an app returns is data, not instructions. Treat tool results as untrusted content in your agent.
  • Each workspace reaches only its own connected accounts.