{"openapi":"3.1.0","info":{"title":"Vellarin Hub API","version":"1.0.0","summary":"The tool layer for AI agents.","description":"One key gives your agent the apps its workspace connected (reads run at once, writes wait for the owner's approval and then run exactly once), plus a shared memory, a run log and eval results. 60 app calls a minute per key. Docs: https://hub.vellarin.ai/docs","contact":{"name":"Vellarin AI","url":"https://vellarin.ai"}},"servers":[{"url":"https://hub.vellarin.ai/api/hub/v1"}],"security":[{"agentKey":[]}],"tags":[{"name":"Apps"},{"name":"Memory"},{"name":"Run log"},{"name":"Evals"},{"name":"Usage"}],"paths":{"/tools":{"get":{"tags":["Apps"],"operationId":"listTools","summary":"The actions this key may call","responses":{"200":{"description":"Tools","content":{"application/json":{"schema":{"type":"object","properties":{"tools":{"type":"array","items":{"$ref":"#/components/schemas/Tool"}}}}}}},"401":{"description":"The key is missing, malformed, unknown or revoked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"A cap or the rate limit was reached. See `scope`, `limit`, `resetsAt` and the Retry-After header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Hub cannot reach what it needs right now. Nothing ran.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/tools/{name}/call":{"post":{"tags":["Apps"],"operationId":"callTool","summary":"Run one action","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string"}},{"name":"wait","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":20},"description":"Keep the request open up to this many seconds for the owner's answer."}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"arguments":{"type":"object","additionalProperties":true}}}}}},"responses":{"200":{"description":"The action ran","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CallResult"}}}},"202":{"description":"A write is waiting for the owner's approval. Nothing was sent.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CallResult"}}}},"401":{"description":"The key is missing, malformed, unknown or revoked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such tool for this key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"The owner rejected it","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CallResult"}}}},"422":{"description":"The app answered with an error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CallResult"}}}},"429":{"description":"A cap or the rate limit was reached. See `scope`, `limit`, `resetsAt` and the Retry-After header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Hub cannot reach what it needs right now. Nothing ran.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/approvals/{id}":{"get":{"tags":["Apps"],"operationId":"getApproval","summary":"Status of an approval this key asked for","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Approval","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"status":{"enum":["pending","approved","rejected"]},"reason":{"type":["string","null"]},"label":{"type":["string","null"]},"createdAt":{"type":"string"},"decidedAt":{"type":["string","null"]}}}}}},"401":{"description":"The key is missing, malformed, unknown or revoked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such approval for this key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"A cap or the rate limit was reached. See `scope`, `limit`, `resetsAt` and the Retry-After header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Hub cannot reach what it needs right now. Nothing ran.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/usage":{"get":{"tags":["Usage"],"operationId":"getUsage","summary":"App calls used this month and this key's own caps","responses":{"200":{"description":"Usage","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"description":"The key is missing, malformed, unknown or revoked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"A cap or the rate limit was reached. See `scope`, `limit`, `resetsAt` and the Retry-After header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Hub cannot reach what it needs right now. Nothing ran.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/memory":{"get":{"tags":["Memory"],"operationId":"listMemory","summary":"Keys of the workspace's shared memory","parameters":[{"name":"prefix","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Keys (up to 200), without values","content":{"application/json":{"schema":{"type":"object","properties":{"keys":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"updatedAt":{"type":"string"},"expiresAt":{"type":["string","null"]}}}},"total":{"type":"integer"}}}}}},"401":{"description":"The key is missing, malformed, unknown or revoked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"A cap or the rate limit was reached. See `scope`, `limit`, `resetsAt` and the Retry-After header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Hub cannot reach what it needs right now. Nothing ran.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/memory/{key}":{"parameters":[{"name":"key","in":"path","required":true,"schema":{"type":"string","pattern":"^[A-Za-z0-9_.:-]{1,200}$"}}],"get":{"tags":["Memory"],"operationId":"getMemory","summary":"Read a value","responses":{"200":{"description":"Value","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MemoryValue"}}}},"401":{"description":"The key is missing, malformed, unknown or revoked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Nothing is stored under that key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"A cap or the rate limit was reached. See `scope`, `limit`, `resetsAt` and the Retry-After header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Hub cannot reach what it needs right now. Nothing ran.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"put":{"tags":["Memory"],"operationId":"setMemory","summary":"Save a value (text; not for secrets)","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["value"],"properties":{"value":{"type":"string","maxLength":16000},"ttl_seconds":{"type":"integer","minimum":60,"maximum":31536000}}}}}},"responses":{"200":{"description":"Saved","content":{"application/json":{"schema":{"type":"object","properties":{"key":{"type":"string"},"saved":{"type":"boolean"},"expiresAt":{"type":["string","null"]}}}}}},"400":{"description":"The value or the key is not valid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"The key is missing, malformed, unknown or revoked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"A cap or the rate limit was reached. See `scope`, `limit`, `resetsAt` and the Retry-After header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Hub cannot reach what it needs right now. Nothing ran.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["Memory"],"operationId":"deleteMemory","summary":"Delete a key","responses":{"200":{"description":"Deleted","content":{"application/json":{"schema":{"type":"object","properties":{"key":{"type":"string"},"deleted":{"type":"boolean"}}}}}},"401":{"description":"The key is missing, malformed, unknown or revoked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"A cap or the rate limit was reached. See `scope`, `limit`, `resetsAt` and the Retry-After header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Hub cannot reach what it needs right now. Nothing ran.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/traces":{"post":{"tags":["Run log"],"operationId":"logTrace","summary":"Write one event, or up to 100 in \"events\"","requestBody":{"required":true,"content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/TraceEvent"},{"type":"object","required":["events"],"properties":{"events":{"type":"array","maxItems":100,"items":{"$ref":"#/components/schemas/TraceEvent"}}}}]}}}},"responses":{"200":{"description":"Logged","content":{"application/json":{"schema":{"type":"object","properties":{"logged":{"type":"integer"},"run":{"type":"string"}}}}}},"400":{"description":"An event is not valid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"The key is missing, malformed, unknown or revoked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"A cap or the rate limit was reached. See `scope`, `limit`, `resetsAt` and the Retry-After header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Hub cannot reach what it needs right now. Nothing ran.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"get":{"tags":["Run log"],"operationId":"getRun","summary":"The events of one run, in order, with its totals","parameters":[{"name":"run","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Run","content":{"application/json":{"schema":{"type":"object","properties":{"run":{"type":"string"},"summary":{"$ref":"#/components/schemas/RunSummary"},"events":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}},"401":{"description":"The key is missing, malformed, unknown or revoked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"A cap or the rate limit was reached. See `scope`, `limit`, `resetsAt` and the Retry-After header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Hub cannot reach what it needs right now. Nothing ran.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/runs":{"get":{"tags":["Run log"],"operationId":"listRuns","summary":"The latest runs with events, tokens, cost, time and errors","responses":{"200":{"description":"Runs","content":{"application/json":{"schema":{"type":"object","properties":{"runs":{"type":"array","items":{"$ref":"#/components/schemas/RunSummary"}}}}}}},"401":{"description":"The key is missing, malformed, unknown or revoked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"A cap or the rate limit was reached. See `scope`, `limit`, `resetsAt` and the Retry-After header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Hub cannot reach what it needs right now. Nothing ran.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/evals":{"post":{"tags":["Evals"],"operationId":"recordEval","summary":"Record one result, or up to 100 in \"results\"","requestBody":{"required":true,"content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/EvalResult"},{"type":"object","required":["results"],"properties":{"results":{"type":"array","maxItems":100,"items":{"$ref":"#/components/schemas/EvalResult"}}}}]}}}},"responses":{"200":{"description":"Recorded","content":{"application/json":{"schema":{"type":"object","properties":{"recorded":{"type":"integer"},"passed":{"type":"integer"}}}}}},"400":{"description":"A result is not valid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"The key is missing, malformed, unknown or revoked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"A cap or the rate limit was reached. See `scope`, `limit`, `resetsAt` and the Retry-After header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Hub cannot reach what it needs right now. Nothing ran.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"get":{"tags":["Evals"],"operationId":"getEvals","summary":"Pass rate and average score per suite","parameters":[{"name":"suite","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Suites","content":{"application/json":{"schema":{"type":"object","properties":{"suites":{"type":"array","items":{"type":"object","properties":{"suite":{"type":"string"},"results":{"type":"integer"},"passRate":{"type":"number"},"avgScore":{"type":"number"},"lastAt":{"type":"string"},"lastRun":{"type":["string","null"]},"lastRunPassRate":{"type":["number","null"]}}}}}}}}},"401":{"description":"The key is missing, malformed, unknown or revoked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"A cap or the rate limit was reached. See `scope`, `limit`, `resetsAt` and the Retry-After header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Hub cannot reach what it needs right now. Nothing ran.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"components":{"securitySchemes":{"agentKey":{"type":"http","scheme":"bearer","description":"An agent key (vhub_…) created on the Developers page of the workspace."}},"schemas":{"Error":{"type":"object","required":["error","message"],"properties":{"error":{"type":"string"},"message":{"type":"string"}},"additionalProperties":true},"Tool":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"},"inputSchema":{"type":"object","additionalProperties":true},"readOnly":{"type":"boolean"}}},"CallResult":{"type":"object","properties":{"status":{"enum":["ok","waiting_approval","rejected","error","rate_limited"]},"approvalId":{"type":["string","null"]},"result":{"type":"string"}}},"MemoryValue":{"type":"object","properties":{"key":{"type":"string"},"value":{"type":"string"},"updatedAt":{"type":"string"},"expiresAt":{"type":["string","null"]}}},"TraceEvent":{"type":"object","required":["run","name"],"properties":{"run":{"type":"string","maxLength":120},"name":{"type":"string","maxLength":120},"kind":{"enum":["llm","tool","step","error"],"default":"step"},"model":{"type":"string"},"input_tokens":{"type":"integer"},"output_tokens":{"type":"integer"},"cost_usd":{"type":"number"},"ms":{"type":"integer"},"status":{"enum":["ok","error"]},"note":{"type":"string","maxLength":500}}},"RunSummary":{"type":"object","properties":{"run":{"type":"string"},"events":{"type":"integer"},"errors":{"type":"integer"},"inputTokens":{"type":"integer"},"outputTokens":{"type":"integer"},"costUsd":{"type":"number"},"ms":{"type":"integer"},"models":{"type":"array","items":{"type":"string"}},"startedAt":{"type":"string"},"lastAt":{"type":"string"}}},"EvalResult":{"type":"object","required":["suite","case"],"properties":{"suite":{"type":"string","maxLength":120},"case":{"type":"string","maxLength":120},"score":{"type":"number","minimum":0,"maximum":1},"pass":{"type":"boolean"},"run":{"type":"string"},"note":{"type":"string","maxLength":500}}}}}}