API Reference

API Documentation

Everything you need to integrate Brio into your workflow. Generate reports, manage consultants, configure white-label branding, and track usage programmatically.

v4 — April 3, 2026

Authentication

All requests require an API key passed in the Authorization header:

Authorization: Bearer brio_sk_live_abc123...

API keys are available on all paid plans. Each account has one API key. Generate, view, and regenerate from the Brio Dashboard (Account → API Keys). Key management is dashboard-only — keys cannot be managed via the API.

The key is shown once on creation. Brio stores a SHA-256 hash — the plaintext cannot be retrieved later.

Base URL

https://app.runbrio.com/api/v1

Consultants

Consultants appear as the authored strategist on generated reports. Each account supports up to 5 consultants.

List Consultants

GET/consultants

{
  "consultants": [
    {
      "id": "d4e5f6a7-b8c9-0d1e-2f3a-4b5c6d7e8f90",
      "name": "Sarah Chen",
      "title": "Senior Digital Strategist",
      "avatar_url": "https://app.runbrio.com/storage/avatars/d4e5f6a7.jpg",
      "cta_url": "https://calendly.com/sarah-chen",
      "is_default": true,
      "created_at": "2026-03-15T10:00:00Z"
    }
  ]
}

Create Consultant

POST/consultants

FieldTypeRequiredDescription
namestringYesFull name (1–60 characters)
titlestringYesJob title (1–80 characters)
photobase64NoHeadshot (JPEG or PNG, max 2 MB). Returned as avatar_url in responses
cta_urlstringNoLink for the report's closing CTA button (Calendly, booking page, or any URL)
is_defaultbooleanNoSet as account default consultant. Only one default allowed per account

Returns 409 if the account already has 5 consultants.

Update Consultant

PATCH/consultants/:id

Same fields as create. Only include fields you want to change.

Delete Consultant

DELETE/consultants/:id

Returns 400 if the consultant is set as the account default.

White Label

Manage your agency's branding applied to all generated reports. Every account has one white-label configuration, created automatically on signup.

Get White Label Config

GET/white-label

{
  "agency_name": "Apex Digital",
  "agency_website": "https://apexdigital.com",
  "logo_url": "https://app.runbrio.com/storage/brand/x1y2z3/logo_light.png",
  "accent_color": "#F59E0B",
  "cta_button_text": "Book a Call",
  "cta_url": "https://calendly.com/apex-digital"
}

Update White Label Config

PATCH/white-label

Only include fields you want to change.

FieldTypeDescription
agency_namestringAgency name (max 80 characters)
agency_websitestringAgency website URL, shown in report footers
logobase64Agency logo (PNG, SVG, or WebP, max 2 MB). Transparent background recommended. Returned as logo_url in responses. Pass null to remove
accent_colorstringBrand accent color (hex, e.g. #F59E0B). Used for progress bars, highlights, and footer links. Pass null to reset
cta_button_textstringButton label on the report's closing CTA page
cta_urlstringButton link URL on the closing CTA page

Reports

List Reports

GET/reports

Returns a paginated list of reports on your account.

Query Parameters

ParamTypeDescription
statusstringFilter by status: pending, processing, complete, failed
sinceISO 8601Only reports created after this timestamp
limitintegerResults per page (default: 20, max: 100)
cursorstringPagination cursor from previous response

Example Response

{
  "reports": [
    {
      "id": "8f3a1b2c-d4e5-6f7a-8b9c-0d1e2f3a4b5c",
      "status": "complete",
      "url": "https://example.com",
      "business_model": "b2b-saas",
      "consultant_id": "d4e5f6a7-b8c9-0d1e-2f3a-4b5c6d7e8f90",
      "created_at": "2026-03-28T14:30:00Z",
      "completed_at": "2026-03-28T14:40:12Z"
    }
  ],
  "has_more": true,
  "next_cursor": "eyJjcmVhdGVkX2F0IjoiMjAyNi..."
}

Create Report

POST/reports

Submit a website URL for analysis. Returns a report object with pending status. Report generation takes approximately 5 minutes.

FieldTypeRequiredDescription
urlstringYesThe website URL to analyze (must be publicly accessible)
consultant_idstringYesConsultant to feature on report
webhook_urlstringNoURL to receive a POST when the report completes or fails

Example Request

curl -X POST https://app.runbrio.com/api/v1/reports \
  -H "Authorization: Bearer brio_sk_live_abc123" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com",
    "consultant_id": "d4e5f6a7-b8c9-0d1e-2f3a-4b5c6d7e8f90",
    "webhook_url": "https://yourapp.com/webhooks/brio"
  }'

Example Response

{
  "id": "8f3a1b2c-d4e5-6f7a-8b9c-0d1e2f3a4b5c",
  "status": "pending",
  "url": "https://example.com",
  "created_at": "2026-03-28T14:30:00Z"
}

If your account already has 3 reports generating, the new report is accepted and queued — it will begin processing automatically when a slot opens.

Deduplication: If you submit the same URL while a report for that URL is still pending or was completed within the last 24 hours, the existing report is returned instead of creating a duplicate.

Get Report

GET/reports/:id

Response — Processing

{
  "id": "8f3a1b2c-d4e5-6f7a-8b9c-0d1e2f3a4b5c",
  "status": "processing",
  "url": "https://example.com",
  "created_at": "2026-03-28T14:30:00Z",
  "progress": 0.45
}

The progress field (0.0–1.0) is derived from the number of completed report sections. Poll this endpoint to track generation progress.

Response — Complete

{
  "id": "8f3a1b2c-d4e5-6f7a-8b9c-0d1e2f3a4b5c",
  "status": "complete",
  "url": "https://example.com",
  "created_at": "2026-03-28T14:30:00Z",
  "completed_at": "2026-03-28T14:40:12Z",
  "business_model": "b2b-saas",
  "consultant_id": "d4e5f6a7-b8c9-0d1e-2f3a-4b5c6d7e8f90",
  "industry_vertical": "Technology",
  "pdf_url": "https://app.runbrio.com/api/v1/reports/8f3a.../pdf",
  "sections": [
    { "title": "Executive Snapshot & Digital Maturity Scorecard", "data_tier": "full" },
    { "title": "Technical & Infrastructure Health", "data_tier": "full" },
    { "title": "SEO & Organic Visibility", "data_tier": "degraded" }
  ]
}

Each report generates an Executive Snapshot plus 10 strategy sections. The sections array lists all completed sections. Each section includes a data_tier field (full, degraded, or partial) indicating the data quality level achieved. The business_model field reflects the detected model (e.g. b2b-saas, b2c-ecommerce, b2c-services) which drives the strategic frameworks used throughout the report.

Response — Failed

{
  "id": "8f3a1b2c-d4e5-6f7a-8b9c-0d1e2f3a4b5c",
  "status": "failed",
  "url": "https://example.com",
  "created_at": "2026-03-28T14:30:00Z",
  "error": "The provided URL could not be resolved"
}

Download PDF

GET/reports/:id/pdf

Returns the generated PDF file. White-label branding is applied based on your configuration.

Delete Report

DELETE/reports/:id

Permanently deletes a report and its associated PDF. This action cannot be undone. Does not restore usage credits.

Returns 204 No Content on success.

Usage

Get Usage

GET/usage

Returns current billing period usage for your account.

{
  "plan": "50 Reports / $299",
  "billing_period": {
    "start": "2026-03-01T00:00:00Z",
    "end": "2026-03-31T23:59:59Z"
  },
  "reports_included": 50,
  "reports_used": 37,
  "reports_remaining": 13,
  "overage_count": 0,
  "overage_rate": "$10.00"
}

Webhooks

If you provide a webhook_url when creating a report, Brio will send a POST request when the report completes or fails.

Webhook Payload — Success

{
  "event": "report.completed",
  "report": {
    "id": "8f3a1b2c-d4e5-6f7a-8b9c-0d1e2f3a4b5c",
    "status": "complete",
    "url": "https://example.com",
    "pdf_url": "https://app.runbrio.com/api/v1/reports/8f3a.../pdf"
  }
}

Webhook Payload — Failure

{
  "event": "report.failed",
  "report": {
    "id": "8f3a1b2c-d4e5-6f7a-8b9c-0d1e2f3a4b5c",
    "status": "failed",
    "url": "https://example.com",
    "error": "Unable to crawl the provided URL"
  }
}

Webhook Security

All webhook payloads include an X-Brio-Signature header for verification.

The signature is an HMAC-SHA256 hex digest of the raw request body, using your webhook signing secret (available in the Dashboard alongside your API key).

Verifying the signature

const crypto = require('crypto');

function verifyWebhook(payload, signature, secret) {
  const expected = crypto
    .createHmac('sha256', secret)
    .update(payload)
    .digest('hex');
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expected)
  );
}

Retry policy: If your endpoint returns a non-2xx status or times out (10s), Brio retries up to 5 times with exponential backoff (1m, 5m, 30m, 2h, 8h). After all retries fail, the webhook is abandoned. You can always poll GET /reports/:id as a fallback.

Deduplication

When you submit a URL via POST /reports, Brio checks whether your account already has a non-failed report for that same URL created within the last 24 hours. If one exists, the existing report is returned (with its current status) instead of creating a duplicate. This applies per-organization and uses the normalized URL for matching.

Rate Limits & Concurrency

  • API requests are rate-limited to 60 requests per minute per API key
  • Report creation (POST /reports) is additionally limited to 10 requests per minute and 50 per hour
  • Up to 3 reports generating concurrently per account (dashboard and API combined). Additional reports are accepted and queued automatically
  • Reports count against your plan's monthly allocation
  • Overage reports are billed at $10 per report
  • Report generation typically completes in approximately 5 minutes

Rate-limited requests receive a 429 response with a Retry-After header.

Status Values

Reports move through four statuses during their lifecycle.

StatusDescription
pendingReport queued for processing
processingAnalysis in progress (scanning, classifying, generating, or rendering)
completeReport ready for download
failedGeneration failed — see error field

Errors

All errors return a consistent format:

{
  "error": {
    "code": "invalid_url",
    "message": "The provided URL could not be resolved"
  }
}
HTTP CodeError CodeDescription
400invalid_urlURL is malformed or unreachable
400invalid_requestMissing or invalid request body fields
400incomplete_profileWhite-label profile is missing required fields (returned with a missing_fields array)
401unauthorizedMissing or invalid API key
402usage_exceededPlan limit reached, overage billing failed
402overage_limit_reachedMonthly overage cap reached (2× plan allocation). Resets next billing cycle
404not_foundResource does not exist or belongs to another account
409consultant_limitMaximum 5 consultants reached
422unreachable_urlURL is valid but the website could not be reached
429rate_limitedToo many requests — retry after cooldown
500internal_errorSomething went wrong on our end
503service_unavailableReport generation is temporarily degraded — retry after Retry-After seconds

Quick Start

# 1. Create a report
REPORT_ID=$(curl -s -X POST https://app.runbrio.com/api/v1/reports \
  -H "Authorization: Bearer brio_sk_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com", "consultant_id": "YOUR_CONSULTANT_ID"}' | jq -r '.id')

# 2. Poll until complete (~5 minutes)
curl -s https://app.runbrio.com/api/v1/reports/$REPORT_ID \
  -H "Authorization: Bearer brio_sk_live_YOUR_KEY"

# 3. Download the PDF
curl -o report.pdf https://app.runbrio.com/api/v1/reports/$REPORT_ID/pdf \
  -H "Authorization: Bearer brio_sk_live_YOUR_KEY"

Changelog

v5 (April 7, 2026) — Trimmed white-label and consultant endpoints to only fields that render in the PDF. Removed: social links, gradients, testimonials, secondary colors, agency phone/tagline/email, CTA headline/body, consultant email/phone/linkedin/booking.

v4 (April 3, 2026) — Full field surface documented for white-label and consultant endpoints. Replaced idempotency with URL-based deduplication. Added report creation rate limits, error codes, and data tier to section responses.

v3 (April 3, 2026) — Tightened API surface to match production capabilities.

v2 (March 30, 2026) — Expanded white-label and consultant endpoints. Rate limit and concurrency documentation.

v1 (March 28, 2026) — Initial draft.