{"openapi":"3.1.0","info":{"title":"Roar AI Cloud API","version":"1.0.0","description":"One key, two surfaces. The **gateway** (`/v1/*`) is OpenAI-compatible — point any OpenAI SDK at it. The **management API** (`/client/*`) lets an agent provision keys, read spend, and deploy apps. Both authenticate with a `roar_live_…` key sent as `Authorization: Bearer <key>`. A key carries scopes (inference, keys:read, keys:write, usage:read, requests:read, apps:read, apps:deploy, projects:write, webhooks:read, webhooks:write); each `/client` route requires a specific one. There is also a hosted MCP server at `POST /mcp` exposing the same operations as tools."},"externalDocs":{"description":"Guides and the interactive reference","url":"https://roar-ai.com/docs"},"servers":[{"url":"https://cloud.roar-ai.com"}],"security":[{"BearerAuth":[]}],"tags":[{"name":"Gateway","description":"OpenAI-compatible inference"},{"name":"Keys","description":"API key management"},{"name":"Usage","description":"Usage, cost, and budgets"},{"name":"Apps","description":"Hosted app deploys"},{"name":"Projects","description":"Grouping + budgets"},{"name":"Webhooks","description":"Outbound event notifications"}],"paths":{"/v1/models":{"get":{"tags":["Gateway"],"summary":"List available models","description":"Models reachable through the gateway, tagged with privacy/provider/modality. Requires the `inference` scope.","responses":{"200":{"description":"A list of models","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModelList"}}}},"401":{"description":"Missing or invalid key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/chat/completions":{"post":{"tags":["Gateway"],"summary":"Create a chat completion","description":"OpenAI-compatible. Streaming (`\"stream\": true`) returns SSE. Routed, metered, and white-labelled. Pass `\"model\": \"auto\"` to have Roar pick the cheapest model that can handle the request; the response names the model that ran. Requires `inference`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChatCompletionRequest"}}}},"responses":{"200":{"description":"A chat completion (or SSE stream)"},"401":{"description":"Missing or invalid key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Budget exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/embeddings":{"post":{"tags":["Gateway"],"summary":"Create embeddings","description":"OpenAI-compatible vector embeddings. Requires `inference`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmbeddingsRequest"}}}},"responses":{"200":{"description":"Embedding vectors"},"401":{"description":"Missing or invalid key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/client/keys":{"get":{"tags":["Keys"],"summary":"List API keys","description":"Never returns key plaintext. Requires `keys:read`.","responses":{"200":{"description":"The account's keys","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyList"}}}},"401":{"description":"Unauthenticated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Key lacks keys:read","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Keys"],"summary":"Create an API key","description":"Returns the plaintext key ONCE. Granting management scopes requires an owner session or a key that already holds them. Requires `keys:write`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateKeyRequest"}}}},"responses":{"201":{"description":"The created key (plaintext shown once)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatedKey"}}}},"401":{"description":"Unauthenticated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Key lacks keys:write / cannot escalate scopes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/client/keys/{id}":{"get":{"tags":["Keys"],"summary":"Get one key","description":"Full key detail: settings, spend windows (total/today/week/month), and budget status. Never returns key plaintext. Requires `keys:read`.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Key detail","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKey"}}}},"404":{"description":"No such key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"tags":["Keys"],"summary":"Update a key","description":"Rename, move project, change scopes, pause/resume (`disabled`), and — owner only — set the spend cap or expiry (`expiresAt`). A revoked key rejects `disabled`.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateKeyRequest"}}}},"responses":{"200":{"description":"The updated key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKey"}}}},"404":{"description":"No such key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["Keys"],"summary":"Revoke or delete a key","description":"Revokes by default (key stops working, stays listed). With `?permanent=true`, deletes the key permanently; usage history is kept.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"permanent","in":"query","schema":{"type":"string","enum":["true"]}}],"responses":{"200":{"description":"Revoked or deleted"},"404":{"description":"No such key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/client/usage":{"get":{"tags":["Usage"],"summary":"Usage summary","description":"Token counts, request volume, latency, and cost. Requires `usage:read`.","parameters":[{"name":"from","in":"query","schema":{"type":"string","format":"date"}},{"name":"to","in":"query","schema":{"type":"string","format":"date"}},{"name":"projectId","in":"query","schema":{"type":"string","format":"uuid"}},{"name":"keyId","in":"query","schema":{"type":"string","format":"uuid"},"description":"Limit to one API key"}],"responses":{"200":{"description":"Usage report","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UsageReport"}}}},"403":{"description":"Key lacks usage:read","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/client/budget":{"get":{"tags":["Usage"],"summary":"Budget status","description":"Real-time spend vs. cap per budgeted scope. Requires `usage:read`.","responses":{"200":{"description":"Budget report","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BudgetReport"}}}},"403":{"description":"Key lacks usage:read","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/client/apps":{"get":{"tags":["Apps"],"summary":"List apps","description":"Hosted apps with their live URL and status. Requires `apps:read`.","responses":{"200":{"description":"Apps","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AppList"}}}},"403":{"description":"Key lacks apps:read","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Apps"],"summary":"Deploy an app","description":"Provision + deploy from a git repo. Returns 202 while it builds; poll progress. Requires `apps:deploy`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeployAppRequest"}}}},"responses":{"202":{"description":"Deploy started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/App"}}}},"403":{"description":"Key lacks apps:deploy","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/client/apps/{id}/progress":{"get":{"tags":["Apps"],"summary":"Deploy progress","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Build/deploy progress + URL","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AppProgress"}}}},"404":{"description":"No such app","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/client/projects":{"get":{"tags":["Projects"],"summary":"List projects","responses":{"200":{"description":"Projects","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectList"}}}}}},"post":{"tags":["Projects"],"summary":"Create a project","description":"Group keys and apps under a shared budget. Requires `projects:write`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProjectRequest"}}}},"responses":{"201":{"description":"The created project","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Project"}}}},"403":{"description":"Key lacks projects:write","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/client/webhooks":{"get":{"tags":["Webhooks"],"summary":"List webhooks","description":"Registered webhooks (never the signing secret). Requires `webhooks:read`.","responses":{"200":{"description":"Webhooks","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookList"}}}},"403":{"description":"Key lacks webhooks:read","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Webhooks"],"summary":"Register a webhook","description":"Returns an HMAC signing secret ONCE. Events: deploy.succeeded/failed, budget.alerting/exceeded, or [\"*\"]. Requires `webhooks:write`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateWebhookRequest"}}}},"responses":{"201":{"description":"The created webhook (secret shown once)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatedWebhook"}}}},"400":{"description":"Invalid or unsafe URL","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Key lacks webhooks:write","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/client/webhooks/{id}":{"patch":{"tags":["Webhooks"],"summary":"Update a webhook","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateWebhookRequest"}}}},"responses":{"200":{"description":"The updated webhook","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Webhook"}}}},"404":{"description":"No such webhook","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["Webhooks"],"summary":"Delete a webhook","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Deleted"},"404":{"description":"No such webhook","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/client/webhooks/{id}/test":{"post":{"tags":["Webhooks"],"summary":"Send a test event","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Test queued"},"404":{"description":"No such webhook","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/client/webhooks/{id}/deliveries":{"get":{"tags":["Webhooks"],"summary":"Recent delivery attempts","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Delivery log","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookDeliveryList"}}}},"404":{"description":"No such webhook","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"components":{"securitySchemes":{"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"roar_live_…","description":"A scoped Roar API key."}},"schemas":{"Error":{"type":"object","properties":{"error":{"type":"object","properties":{"message":{"type":"string"},"type":{"type":"string"},"code":{"type":"string"}}}}},"ModelList":{"type":"object","properties":{"object":{"type":"string"},"data":{"type":"array","items":{"$ref":"#/components/schemas/Model"}}}},"Model":{"type":"object","properties":{"id":{"type":"string"},"object":{"type":"string"},"roar_privacy":{"type":"string"},"roar_modalities":{"type":"array","items":{"type":"string"}}}},"ChatCompletionRequest":{"type":"object","required":["model","messages"],"properties":{"model":{"type":"string","description":"A model id from /v1/models"},"messages":{"type":"array","items":{"type":"object","properties":{"role":{"type":"string"},"content":{"type":"string"}}}},"stream":{"type":"boolean","default":false},"temperature":{"type":"number"},"tools":{"type":"array","items":{"type":"object"}}}},"EmbeddingsRequest":{"type":"object","required":["model","input"],"properties":{"model":{"type":"string"},"input":{"oneOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}]}}},"ApiKey":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string","nullable":true},"prefix":{"type":"string"},"scopes":{"type":"array","items":{"type":"string","enum":["inference","keys:read","keys:write","usage:read","requests:read","apps:read","apps:deploy","projects:write","webhooks:read","webhooks:write"]}},"projectId":{"type":"string","format":"uuid","nullable":true},"spendLimitUsd":{"type":"string","nullable":true},"revoked":{"type":"string","format":"date-time","nullable":true}}},"ApiKeyList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ApiKey"}}}},"CreateKeyRequest":{"type":"object","properties":{"name":{"type":"string"},"projectId":{"type":"string","format":"uuid","nullable":true},"scopes":{"type":"array","items":{"type":"string","enum":["inference","keys:read","keys:write","usage:read","requests:read","apps:read","apps:deploy","projects:write","webhooks:read","webhooks:write"]},"default":["inference"]},"spendLimitUsd":{"type":"number","nullable":true},"budgetPeriod":{"type":"string","enum":["day","week","month","total"]}}},"UpdateKeyRequest":{"type":"object","properties":{"name":{"type":"string","nullable":true},"projectId":{"type":"string","format":"uuid","nullable":true},"scopes":{"type":"array","items":{"type":"string","enum":["inference","keys:read","keys:write","usage:read","requests:read","apps:read","apps:deploy","projects:write","webhooks:read","webhooks:write"]}}}},"CreatedKey":{"allOf":[{"$ref":"#/components/schemas/ApiKey"},{"type":"object","properties":{"key":{"type":"string","description":"Plaintext — shown once"},"warning":{"type":"string"}}}]},"UsageReport":{"type":"object","properties":{"summary":{"type":"object"},"byModel":{"type":"array","items":{"type":"object"}}}},"BudgetReport":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"scope":{"type":"string"},"spendUsd":{"type":"number"},"spendLimitUsd":{"type":"number"},"state":{"type":"string","enum":["ok","alerting","exceeded"]}}}}}},"App":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"status":{"type":"string"},"url":{"type":"string","nullable":true}}},"AppList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/App"}}}},"AppProgress":{"type":"object","properties":{"status":{"type":"string"},"url":{"type":"string","nullable":true}}},"DeployAppRequest":{"type":"object","required":["name","repo"],"properties":{"name":{"type":"string"},"repo":{"type":"string","description":"owner/name"},"branch":{"type":"string"},"env":{"type":"object","additionalProperties":{"type":"string"}},"projectId":{"type":"string","format":"uuid","nullable":true}}},"Project":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"spendLimitUsd":{"type":"string","nullable":true},"budgetPeriod":{"type":"string"}}},"ProjectList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Project"}}}},"CreateProjectRequest":{"type":"object","required":["name"],"properties":{"name":{"type":"string"},"spendLimitUsd":{"type":"number","nullable":true},"budgetPeriod":{"type":"string","enum":["day","week","month","total"]}}},"WebhookEvent":{"type":"string","enum":["deploy.succeeded","deploy.failed","budget.alerting","budget.exceeded","*"]},"Webhook":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"url":{"type":"string","format":"uri"},"events":{"type":"array","items":{"$ref":"#/components/schemas/WebhookEvent"}},"description":{"type":"string","nullable":true},"enabled":{"type":"boolean"},"lastStatus":{"type":"integer","nullable":true},"lastDeliveryAt":{"type":"string","format":"date-time","nullable":true}}},"WebhookList":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Webhook"}},"events":{"type":"array","items":{"$ref":"#/components/schemas/WebhookEvent"}}}},"CreateWebhookRequest":{"type":"object","required":["url"],"properties":{"url":{"type":"string","format":"uri","description":"Public https endpoint"},"events":{"type":"array","items":{"$ref":"#/components/schemas/WebhookEvent"},"default":["*"]},"description":{"type":"string"}}},"UpdateWebhookRequest":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"events":{"type":"array","items":{"$ref":"#/components/schemas/WebhookEvent"}},"description":{"type":"string","nullable":true},"enabled":{"type":"boolean"}}},"CreatedWebhook":{"allOf":[{"$ref":"#/components/schemas/Webhook"},{"type":"object","properties":{"secret":{"type":"string","description":"HMAC signing secret — shown once"},"warning":{"type":"string"}}}]},"WebhookDeliveryList":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"event":{"type":"string"},"status":{"type":"string","enum":["pending","delivered","failed"]},"attempts":{"type":"integer"},"responseStatus":{"type":"integer","nullable":true}}}}}}}}}