Business Dashboard API

Programmatic access for external integrations. RESTful, JSON, simple Bearer auth.

Base URL: https://your-domain.com/api/v1

πŸ”‘ Get an API key

API keys are created and revoked by a dashboard admin. To generate one:

  1. Sign in to the dashboard at the dashboard root (must be an admin account).
  2. Click the Settings tab in the top nav.
  3. Scroll to the API keys section.
  4. Click + New API key, pick a descriptive name (e.g. β€œSOC2 platform”), choose the scopes the consumer needs, and click Create.
  5. Copy the key immediately β€” it's shown ONCE. Format: dsk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Lost a key? You can't recover it β€” revoke the old one and generate a new one. The same Settings β†’ API keys page shows when each key was last used so you can spot stale or compromised keys.

Authentication

Every request must include an Authorization header with a Bearer token.

Authorization: Bearer dsk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Errors

StatusMeaning
401Missing or invalid Bearer token, or key has been revoked.
403Key is valid but doesn't have the scope required for this endpoint.
404Unknown endpoint or resource not found.
429Rate limit exceeded. Response includes a Retry-After header (seconds) and an X-RateLimit-Remaining header.
500/503Server error, or upstream service (DigitalOcean, SalesCRM) is unavailable.

Rate limits

Each API key gets a token bucket: 100 requests burst, refilled at 1 per second (effectively ~60/minute sustained). That's plenty for normal use including initial big pulls (e.g. fetching all 500 security findings in one go).

The bucket is keyed on the API key's ID, not IP β€” so the same key from multiple deployments shares one bucket. If you need higher throughput, request a second key (each key gets its own bucket).

When the bucket is empty you'll get a 429 with Retry-After telling you exactly how many seconds to wait. A simple retry-with-backoff loop is the right client behavior.

Scopes

Each key has either admin (full access) or a list of scopes. An endpoint's required scope is listed with the endpoint below.

ScopeGrants access to
appsApp catalog (GitHub repos + manual deployment mappings)
notesKnowledge wiki + user-created notes
documentsUploaded files (PDFs, Word docs)
serversDigitalOcean droplets, databases, spaces
financeFinance Plus β€” transactions, vendors, budgets, recurring costs
hrHR & Payroll β€” employees, leave, payroll runs
securitySOC2 security findings across all repos β€” vulnerabilities, secrets, branch protection
adminFull access. Reserved for trusted internal services only.

Endpoints

GET/api/v1/merequires scope: any valid key

Returns the calling API key's identity, scopes, and admin status. Useful for verifying your key works.

Example request

curl \
  -H "Authorization: Bearer dsk_xxxxxxxxxxxx" \
  $BASE_URL/api/v1/me

Example response

{
  "keyId": 3,
  "name": "SOC2 platform",
  "isAdmin": false,
  "permissions": ["apps", "servers"],
  "createdBy": "james@jamesbratton.me"
}
GET/api/v1/appsrequires scope: apps

Lists all known apps β€” GitHub repos plus manual app-to-droplet mappings recorded in the dashboard.

Example request

curl \
  -H "Authorization: Bearer dsk_xxxxxxxxxxxx" \
  $BASE_URL/api/v1/apps

Example response

{
  "count": 28,
  "apps": [
    {
      "slug": "jbratton45/omniforgehq",
      "name": "omniforgehq",
      "language": "TypeScript",
      "pushedAt": "2026-05-22T10:30:00Z",
      "url": "https://github.com/jbratton45/omniforgehq"
    }
  ],
  "deployments": [
    {
      "appName": "OmniForgeHQ",
      "dropletId": 12345678,
      "dropletName": "Omni-Suite-Plainfield",
      "url": "https://omniforgehq.com",
      "githubRepo": "jbratton45/omniforgehq",
      "notes": null
    }
  ]
}
GET/api/v1/dropletsrequires scope: servers

Lists DigitalOcean droplets with cost, status, networking, and tags.

Example request

curl \
  -H "Authorization: Bearer dsk_xxxxxxxxxxxx" \
  $BASE_URL/api/v1/droplets

Example response

{
  "count": 3,
  "totalMonthlyEstimate": 144.00,
  "droplets": [
    {
      "id": 12345678,
      "name": "Omni-Suite-Plainfield",
      "status": "active",
      "publicIp": "192.0.2.15",
      "region": "New York 1",
      "size": "s-4vcpu-8gb",
      "memoryGb": 8,
      "vcpus": 4,
      "diskGb": 160,
      "monthlyCost": 48.00,
      "tags": [],
      "createdAt": "2025-08-12T14:22:00Z"
    }
  ]
}
GET/api/v1/financerequires scope: finance

Finance Plus overview from the in-house SalesCRM: income/expense in last 30 days, recurring burn, vendor count, business line count.

Example request

curl \
  -H "Authorization: Bearer dsk_xxxxxxxxxxxx" \
  $BASE_URL/api/v1/finance

Example response

{
  "asOf": "2026-05-23",
  "totalTransactions": 42,
  "recentIncome": 18450.00,
  "recentExpense": 7920.50,
  "totalRecurringMonthly": 1245.00,
  "vendorCount": 12,
  "businessLineCount": 9,
  "budgetCount": 4
}
GET/api/v1/securityrequires scope: security

SOC2 security findings across all monitored repos. Each finding is mapped to its SOC2 control (CC6.1 access, CC7.1 vulnerability mgmt, CC8.1 change mgmt). Designed to be polled by the SOC2 preparedness platform for compliance evidence. Query params: state, severity, category, control (e.g. 'CC7.1'), repo, limit, summary.

Example request

curl \
  -H "Authorization: Bearer dsk_xxxxxxxxxxxx" \
  $BASE_URL/api/v1/security

Example response

{
  "asOf": "2026-05-23T11:42:00Z",
  "appliedFilters": { "state": "open", "limit": 500 },
  "count": 27,
  "summary": {
    "totalOpen": 27,
    "openBySeverity": { "high": 27 },
    "openByCategory": { "branch_protection": 27 },
    "openByControl": { "CC8.1": 27 },
    "resolvedLast30Days": 0
  },
  "findings": [
    {
      "id": 1,
      "source": "github-branch-protection",
      "repo": "jbratton45/omniforgehq",
      "title": "Default branch 'main' has no protection rules",
      "severity": "high",
      "state": "open",
      "category": "branch_protection",
      "soc2Control": "CC8.1",
      "firstSeenAt": "2026-05-23T11:42:00Z",
      "url": "https://github.com/jbratton45/omniforgehq/settings/branches"
    }
  ]
}
GET/api/v1/hrrequires scope: hr

HR & Payroll overview: employee counts, who's on leave today, pending leave requests, latest payroll run.

Example request

curl \
  -H "Authorization: Bearer dsk_xxxxxxxxxxxx" \
  $BASE_URL/api/v1/hr

Example response

{
  "asOf": "2026-05-23",
  "totalEmployees": 8,
  "activeEmployees": 8,
  "onLeaveToday": 1,
  "pendingLeaveRequests": 2,
  "latestPayroll": {
    "month": 4,
    "year": 2026,
    "totalGross": 32500.00,
    "totalNet": 24875.00,
    "employeeCount": 8,
    "status": "paid"
  }
}
GET/api/v1/hostingerrequires scope: servers

Hostinger VPS instances and owned domains. Useful if your infrastructure is split between DigitalOcean (queried via /droplets) and Hostinger.

Example request

curl \
  -H "Authorization: Bearer dsk_xxxxxxxxxxxx" \
  $BASE_URL/api/v1/hostinger

Example response

{
  "vps": [
    {
      "id": 4521,
      "hostname": "vps-prod-1",
      "state": "running",
      "publicIp": "203.0.113.42",
      "plan": "KVM 4",
      "monthlyCost": 19.99,
      "cpus": 4,
      "memoryGb": 16,
      "diskGb": 200
    }
  ],
  "domains": [
    {
      "domain": "example.com",
      "expiresAt": "2027-03-15T00:00:00Z",
      "autoRenew": true
    }
  ]
}
GET/api/v1/toolsrequires scope: admin

Tracked tools and subscriptions registry. Admin-scope only β€” the records include cost data and references to where credentials live (vault entries, 1Password vaults, etc.).

Example request

curl \
  -H "Authorization: Bearer dsk_xxxxxxxxxxxx" \
  $BASE_URL/api/v1/tools

Example response

{
  "count": 23,
  "totalMonthlyEstimate": 487.50,
  "tools": [
    {
      "id": 7,
      "name": "GitHub",
      "category": "development",
      "monthlyCost": 21.00,
      "owner": "james@jamesbratton.me",
      "url": "https://github.com",
      "credentialsHint": "Vault entry #3"
    }
  ]
}