OpsBlu API docs | OpsBlu Docs

OpsBlu API

One dataset, two doors. REST for code and integrations, MCP for agents. Both read the same records and spend the same credits.

What you get

Every US local business we track, refreshed continuously, with:

  • Identity & location: name, category (controlled vocabulary), address, city, state, ZIP, status (active / closed).
  • Contact: published phone, business/role inboxes, website, socials. Never named-person data.
  • Website: platform, Core Web Vitals (LCP / CLS / INP, pass/fail), SEO basics (title, meta, H1, schema, sitemap, robots), SSL issue date.
  • Marketing: analytics tools, ad platforms, pixels, server-side tracking yes/no, consent tool.
  • Signals: hot (new or changed in the last 30 days), new_in_days, a change log (new_business, site_launched, platform_changed, pixel_added, pixel_removed, closed).

No reviews, star ratings or photos. Ever. See methodology for sources, freshness and accuracy.

Authentication

Create a key at /app/api-keys (creating your first key also grants the +750 connect bonus). Send it as a bearer token. Keys can carry their own monthly spend cap; the account cap always applies too.

headerhttp
Authorization: Bearer ob_live_c9b298ba67d3…

Browser sessions in the app use the same endpoints with a session token. Free aggregate endpoints need no credential at all.

Free vs paid

EndpointCostReturns
GET /v1/coverageFree, no keyCollection counters, covered cities
GET /v1/stats, POST /v1/stats/polygonFree, no keyCounts and breakdowns. Never names, IDs or coordinates. Counts under 5 come back as "<5".
GET /v1/categoriesFree, no keyThe category vocabulary with national counts
GET /v1/businessesFreeNames + signals + a cost estimate. No contacts.
GET /v1/businesses/{id}3 credits, 10 if hotThe full record including phone, emails, website
GET /v1/changesFree listChange events with business summaries; opening a record bills as above
POST /v1/exports → /confirmPer record, charged on confirmCSV of full records
POST /v1/report-cardFreeWebsite score for one domain

Credits

1 credit = $0.01. Prepaid, no subscription.

  • Standard record: 3 credits ($0.03).
  • Hot record (new or changed in the last 30 days): 10 credits ($0.10).
  • Once per unique record per calendar month. Open the same business twice in October, pay once. Exports skip records you already opened this month.
  • Free credits: 250 on signup with a business email (one grant per domain), +750 when you create an API key / connect MCP or install TagFrog on a client site. Free credits expire after 30 days.
  • Spend caps: per account (PUT /v1/billing/spend-cap) and per key. Over the cap, paid calls return 402 spend_cap; nothing else breaks.

Every paid response includes credits_used and balance_remaining so an agent can reason about budget without an extra call.

paid response envelopejson
{
  "record": { "id": "ob_por_den_0007", "name": "…", "phone": "(503) 555-0142", "emails": ["office@…"], "web": {…}, "marketing": {…}, "signals": {"hot": false, …} },
  "credits_used": 3,
  "balance_remaining": 1247,
  "already_revealed": false
}

Quick start

Three calls: a free aggregate, a free search, one paid reveal.

quick startbash
# 1. Free: how many dentists in Portland, and how many fail Core Web Vitals?
curl "https://opsblu.com/v1/stats?state=oregon&city=portland&category=dentists"

# 2. Free: list the failing ones (names + signals, no contacts) with a cost estimate
curl -H "Authorization: Bearer ob_live_YOUR_KEY" \
  "https://opsblu.com/v1/businesses?state=oregon&city=portland&category=dentists&cwv_fail=true&limit=25"

# 3. Paid: open one record (3 credits, 10 if hot)
curl -H "Authorization: Bearer ob_live_YOUR_KEY" "https://opsblu.com/v1/businesses/ob_por_den_0007"

Prefer an agent? Connect via MCP and ask: "How many dentists in Portland fail Core Web Vitals? Show me 10, don't open any records yet."

Rate limits

Anonymous and free endpoints are limited per IP (about 120 requests a minute). Keys get higher limits. Over the limit you get a 429 with a friendly body, not an error wall. Back off for retry_after seconds and continue.

429 slow_downjson
{ "error": "slow_down", "message": "You're moving fast. Give it a few seconds and try again.", "retry_after": 12 }

Abuse controls (coverage-ratio throttling, progressive latency, per-key caps, canary records) run server-side. Scrape-like access patterns slow down before they stop.

Errors

All errors are JSON: { "error": "<code>", "message": "<human text>" }.

HTTPerrorMeaning
400bad_requestMissing or invalid parameter; the message says which.
401auth_requiredPaid endpoint with no credential.
401auth_invalidKey revoked or token expired.
402insufficient_creditsBalance too low. Top up at /app/billing.
402spend_capMonthly spend cap reached (account or key).
403business_email_requiredFree-credit grants need a business email domain. You can still buy credits.
404not_foundUnknown id, slug or token.
409already_granted / bad_stateBonus already claimed; export already confirmed.
410expiredSample link past its 60-day window.
429slow_downRate limited; honor retry_after.

Recipes

Each recipe is a real task written twice: as REST calls and as an agent prompt.

What we measure

On our own site we track these product events (via TagFrog → GA4): search_submitted, draw_completed, category_chip_clicked, persona_selected, email_gate_shown, email_captured, signup_completed, free_credits_granted, mcp_connected, report_card_run, sample_page_viewed, sample_cta_clicked, topup_started, topup_completed, record_revealed, export_confirmed, territory_saved, alert_configured, removal_requested. We do not track your API calls beyond what billing requires. Details in privacy.