{"openapi":"3.1.0","info":{"title":"Business Dashboard Public API","version":"1.0.0","description":"Programmatic, key-authenticated access to the business dashboard: app catalog, infrastructure, finance/HR overviews, security findings, tracked tools, and quick capture.\n\n**Authentication** — every endpoint requires a Dashboard Secret Key:\n\n```\nAuthorization: Bearer dsk_xxxxxxxxxxxxxxxxxxxx\n```\n\nKeys are minted in the dashboard (Settings → API Keys). A key is either **admin** (full access) or **scoped** to a set of permissions. Each endpoint below documents the scope it needs; admin keys satisfy every scope.\n\n**Rate limiting** — requests are limited per key; exceeding the limit returns `429`.","contact":{"name":"Dashboard owner","email":"jbratton45@gmail.com"}},"servers":[{"url":"https://businessdashboard.click","description":"Production"}],"security":[{"bearerAuth":[]}],"tags":[{"name":"Identity","description":"Verify a key and see what it can access."},{"name":"Apps","description":"App catalog and deployments."},{"name":"Infrastructure","description":"Servers, VPS, and domains."},{"name":"Finance","description":"Finance overview (in-house Finance Plus)."},{"name":"HR","description":"HR overview."},{"name":"Security","description":"Security findings (SOC2 evidence)."},{"name":"Tools","description":"Tracked tools / subscriptions."},{"name":"Capture","description":"Quick-capture inbox for thoughts."},{"name":"Build","description":"Scope an idea → AI builds it → opens a PR (admin)."}],"paths":{"/api/v1/build-requests":{"post":{"tags":["Build"],"summary":"Queue an AI build (opens a PR)","description":"Scope an idea and have the agent implement it in the target repo on a new branch, then open a PR. **Nothing is deployed — the PR is the approval gate.** Runs the agent in a sandboxed non-root user. Returns immediately; poll the returned URL. **Requires an admin key.**","operationId":"createBuildRequest","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["repo","idea"],"properties":{"repo":{"type":"string","description":"\"owner/name\"."},"idea":{"type":"string","maxLength":8000,"description":"The feature/change to build."}}}}}},"responses":{"202":{"description":"Queued.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"integer"},"status":{"type":"string"},"repo":{"type":"string"},"poll":{"type":"string","description":"URL to poll for status."}}}}}},"400":{"description":"repo must be 'owner/name'; idea required and ≤ 8000 chars.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key. Provide `Authorization: Bearer dsk_...`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"An admin key is required.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded for this key. Retry after a short wait.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"get":{"tags":["Build"],"summary":"List recent build requests","description":"Most recent build requests and their status. **Requires an admin key.**","operationId":"listBuildRequests","responses":{"200":{"description":"Build requests.","content":{"application/json":{"schema":{"type":"object","properties":{"count":{"type":"integer"},"requests":{"type":"array","items":{"$ref":"#/components/schemas/BuildRequest"}}}}}}},"401":{"description":"Missing or invalid API key. Provide `Authorization: Bearer dsk_...`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"An admin key is required.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/build-requests/{id}":{"get":{"tags":["Build"],"summary":"Get a build request's status","description":"Poll this until `status` is `succeeded` (see `prUrl`) or `failed` (see `error`). **Requires an admin key.**","operationId":"getBuildRequest","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Build request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BuildRequest"}}}},"401":{"description":"Missing or invalid API key. Provide `Authorization: Bearer dsk_...`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"An admin key is required.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No build request with that id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/repos/ask":{"post":{"tags":["Apps"],"summary":"Ask a question about one repository","description":"Answers a question grounded ONLY on a single tagged repository (plus wiki notes that mention it) — for the discussion platform's repo-scoped Q&A. Use the `slug` from `GET /api/v1/apps` as `repo`. Stateless. **Scope:** `apps`.","operationId":"askRepo","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["repo","question"],"properties":{"repo":{"type":"string","description":"Repository slug \"owner/name\".","examples":["jbratton45/omniforgehq"]},"question":{"type":"string","maxLength":2000,"description":"The question to answer about this repo."}}}}}},"responses":{"200":{"description":"Answer (check `found`; false means the repo isn't known).","content":{"application/json":{"schema":{"type":"object","properties":{"repo":{"type":"string"},"found":{"type":"boolean"},"answer":{"type":"string"},"relatedNotes":{"type":"integer","description":"Count of wiki notes folded into context."}}}}}},"400":{"description":"`repo` and `question` are required; question must be ≤ 2000 chars.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key. Provide `Authorization: Bearer dsk_...`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Valid key, but it lacks the scope this endpoint requires.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded for this key. Retry after a short wait.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/me":{"get":{"tags":["Identity"],"summary":"Who am I","description":"Returns the calling key's identity, scopes, and admin status. Any valid key may call this — useful for verifying a key works.","operationId":"getMe","responses":{"200":{"description":"Key identity.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KeyIdentity"}}}},"401":{"description":"Missing or invalid API key. Provide `Authorization: Bearer dsk_...`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded for this key. Retry after a short wait.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/apps":{"get":{"tags":["Apps"],"summary":"List apps and deployments","description":"App catalog — GitHub repos plus manual app-to-droplet deployment mappings. **Scope:** `apps`.","operationId":"listApps","responses":{"200":{"description":"Apps and deployments.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AppsResponse"}}}},"401":{"description":"Missing or invalid API key. Provide `Authorization: Bearer dsk_...`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Valid key, but it lacks the scope this endpoint requires.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded for this key. Retry after a short wait.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/droplets":{"get":{"tags":["Infrastructure"],"summary":"List DigitalOcean droplets","description":"DigitalOcean droplets with cost estimates. **Scope:** `servers`.","operationId":"listDroplets","responses":{"200":{"description":"Droplets.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DropletsResponse"}}}},"401":{"description":"Missing or invalid API key. Provide `Authorization: Bearer dsk_...`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Valid key, but it lacks the scope this endpoint requires.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded for this key. Retry after a short wait.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"DigitalOcean is not configured on the server.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/hostinger":{"get":{"tags":["Infrastructure"],"summary":"List Hostinger VPS and domains","description":"Hostinger VPS instances and registered domains. **Scope:** `servers`.","operationId":"listHostinger","responses":{"200":{"description":"VPS and domains.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HostingerResponse"}}}},"401":{"description":"Missing or invalid API key. Provide `Authorization: Bearer dsk_...`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Valid key, but it lacks the scope this endpoint requires.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded for this key. Retry after a short wait.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Hostinger is not configured on the server.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/finance":{"get":{"tags":["Finance"],"summary":"Finance overview","description":"Finance summary from the in-house Finance Plus module. **Scope:** `finance`.","operationId":"getFinanceOverview","responses":{"200":{"description":"Finance overview.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FinanceOverview"}}}},"401":{"description":"Missing or invalid API key. Provide `Authorization: Bearer dsk_...`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Valid key, but it lacks the scope this endpoint requires.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded for this key. Retry after a short wait.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Finance Plus / SalesCRM is not configured on the server.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/hr":{"get":{"tags":["HR"],"summary":"HR overview","description":"HR summary from the in-house module. **Scope:** `hr`.","operationId":"getHrOverview","responses":{"200":{"description":"HR overview (shape depends on configured HR data).","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"401":{"description":"Missing or invalid API key. Provide `Authorization: Bearer dsk_...`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Valid key, but it lacks the scope this endpoint requires.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded for this key. Retry after a short wait.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"HR source is not configured on the server.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/security":{"get":{"tags":["Security"],"summary":"List security findings","description":"Current security findings + an optional summary, for SOC2 evidence collection. **Scope:** `security`.","operationId":"listSecurityFindings","parameters":[{"name":"state","in":"query","description":"Finding state filter.","schema":{"type":"string","enum":["open","resolved","dismissed","fixed"],"default":"open"}},{"name":"severity","in":"query","schema":{"type":"string","enum":["critical","high","medium","low","info"]}},{"name":"category","in":"query","schema":{"type":"string"},"description":"e.g. vulnerable_dependency, secret."},{"name":"control","in":"query","schema":{"type":"string"},"description":"SOC2 control ID, e.g. CC7.1."},{"name":"repo","in":"query","schema":{"type":"string"},"description":"owner/repo."},{"name":"limit","in":"query","schema":{"type":"integer","default":500}},{"name":"summary","in":"query","description":"Include the summary block.","schema":{"type":"boolean","default":true}}],"responses":{"200":{"description":"Findings.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SecurityResponse"}}}},"401":{"description":"Missing or invalid API key. Provide `Authorization: Bearer dsk_...`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Valid key, but it lacks the scope this endpoint requires.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded for this key. Retry after a short wait.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/tools":{"get":{"tags":["Tools"],"summary":"List tracked tools / subscriptions","description":"Tracked tools and subscriptions with monthly cost estimates. Sensitive (cost + credential references): **requires an admin key.**","operationId":"listTools","responses":{"200":{"description":"Tools.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToolsResponse"}}}},"401":{"description":"Missing or invalid API key. Provide `Authorization: Bearer dsk_...`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"An admin key is required for this endpoint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded for this key. Retry after a short wait.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/capture":{"post":{"tags":["Capture"],"summary":"Capture a thought to the inbox","description":"Drop any thought into the quick-capture inbox. Accepts JSON `{content, source?}` or a raw `text/plain` body (the whole body becomes the capture). Any valid key may capture.","operationId":"createCapture","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["content"],"properties":{"content":{"type":"string","description":"The thought to capture."},"source":{"type":"string","description":"Origin label.","default":"shortcut"}}}},"text/plain":{"schema":{"type":"string","description":"Raw text; the entire body is captured."}}}},"responses":{"201":{"description":"Captured.","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"id":{"type":"integer"}}}}}},"400":{"description":"`content` is required / empty.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key. Provide `Authorization: Bearer dsk_...`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded for this key. Retry after a short wait.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"dsk_*","description":"Dashboard Secret Key. Format: `dsk_` followed by a random token."}},"schemas":{"Error":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string","description":"Optional machine-readable code."}},"required":["error"]},"KeyIdentity":{"type":"object","properties":{"keyId":{"type":"integer"},"name":{"type":"string"},"isAdmin":{"type":"boolean"},"permissions":{"type":"array","items":{"type":"string"}},"createdBy":{"type":"string"}}},"AppsResponse":{"type":"object","properties":{"count":{"type":"integer"},"apps":{"type":"array","items":{"type":"object","properties":{"slug":{"type":"string","description":"owner/repo."},"name":{"type":"string"},"language":{"type":["string","null"]},"pushedAt":{"type":["string","null"],"format":"date-time"},"url":{"type":["string","null"]}}}},"deployments":{"type":"array","items":{"type":"object","properties":{"appName":{"type":"string"},"dropletId":{"type":["integer","null"]},"dropletName":{"type":["string","null"]},"url":{"type":["string","null"]},"githubRepo":{"type":["string","null"]},"notes":{"type":["string","null"]}}}}}},"DropletsResponse":{"type":"object","properties":{"count":{"type":"integer"},"totalMonthlyEstimate":{"type":"number"},"droplets":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer"},"name":{"type":"string"},"status":{"type":"string"},"publicIp":{"type":["string","null"]},"region":{"type":"string"},"size":{"type":"string"},"memoryGb":{"type":"number"},"vcpus":{"type":"integer"},"diskGb":{"type":"integer"},"monthlyCost":{"type":"number"},"tags":{"type":"array","items":{"type":"string"}},"createdAt":{"type":"string","format":"date-time"}}}}}},"HostingerResponse":{"type":"object","properties":{"vps":{"type":"array","items":{"type":"object","properties":{"id":{"type":["integer","string"]},"hostname":{"type":"string"},"state":{"type":"string"},"publicIp":{"type":["string","null"]},"plan":{"type":["string","null"]},"monthlyCost":{"type":"number"},"cpus":{"type":"integer"},"memoryMb":{"type":"integer"},"diskGb":{"type":"integer"}}}},"domains":{"type":"array","items":{"type":"object","properties":{"domain":{"type":"string"},"status":{"type":"string"},"registeredAt":{"type":["string","null"]},"expiresAt":{"type":["string","null"]},"autoRenew":{"type":"boolean"}}}}}},"FinanceOverview":{"type":"object","description":"Summary figures from Finance Plus.","properties":{"asOf":{"type":"string","format":"date-time"},"totalTransactions":{"type":"integer"},"recentIncome":{"type":"number"},"recentExpense":{"type":"number"},"totalRecurringMonthly":{"type":"number"},"vendorCount":{"type":"integer"},"businessLineCount":{"type":"integer"},"budgetCount":{"type":"integer"}},"additionalProperties":true},"SecurityResponse":{"type":"object","properties":{"asOf":{"type":"string","format":"date-time"},"appliedFilters":{"type":"object","additionalProperties":true},"count":{"type":"integer"},"summary":{"type":"object","additionalProperties":true},"findings":{"type":"array","items":{"type":"object","additionalProperties":true}}}},"ToolsResponse":{"type":"object","properties":{"count":{"type":"integer"},"totalMonthlyEstimate":{"type":"number"},"tools":{"type":"array","items":{"type":"object","additionalProperties":true}}}},"BuildRequest":{"type":"object","properties":{"id":{"type":"integer"},"repo":{"type":"string"},"idea":{"type":"string"},"status":{"type":"string","enum":["queued","running","succeeded","failed"]},"branch":{"type":["string","null"]},"prUrl":{"type":["string","null"]},"result":{"type":["string","null"],"description":"Agent summary."},"error":{"type":["string","null"]},"createdBy":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}}}}}