Every metric your team acts on eventually leaves the tool that produced it. Search rankings end up in weekly decks. Ad spend lands in a BI warehouse. Revenue lives in three dashboards at once. Data that stays locked inside its own product gets checked when someone remembers, which in practice means less and less often.
We didn't want AI visibility to be that metric. So BrandGEO now ships a public API: API v1, a read-only REST interface over everything your account already contains, plus an official Laravel client that turns it into typed PHP.
What this unlocks
A few concrete uses, all pulled from why we built it:
- BI and reporting. Pipe visibility scores and share-of-voice numbers into the warehouse next to traffic and revenue, and let your existing reporting stack chart the trend.
- Client dashboards. Agencies can render BrandGEO data inside their own branded portals. Our Nova dashboard package does exactly this, and it's built entirely on the public API described here, with no private endpoints.
- Internal alerting. Poll weekly snapshots and raise a Slack message from your own tooling when a score moves.
- Automated deliverables. Generate a monthly summary per brand from audits and trend data, on your schedule and in your format.
Two design decisions matter for anyone building on top of this:
It's read-only. The API reports; it doesn't mutate. You can't create audits or edit monitors through it, which keeps the security surface small. A leaked key can read your visibility data, not burn your audit quota.
The v1 contract is frozen. Fields may be added over time, but nothing in v1 gets renamed or removed. Breaking changes would ship as /api/v2. Code written against v1 today keeps working.
Keys, limits, and access
Authentication is a bearer token. Each user generates one API key at Settings → API in the BrandGEO app. The key is shown once and stored hashed (sha256), and regenerating immediately revokes the previous one.
The key inherits your account's plan and paywall state. Rate limits are 120 requests per minute on paid and free accounts, and 30 per minute on trials. A 429 response includes Retry-After and X-RateLimit-* headers, so well-behaved clients can back off automatically.
The endpoint tour
Base URL: https://brandgeo.co/api/v1. Single resources come wrapped as {"data": {...}}, lists add links and meta.
GET https://brandgeo.co/api/v1/account
Authorization: Bearer 1|xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
{
"data": {
"id": 1, "name": "...", "email": "...",
"subscription": {"status": "active", "plan": "Business", "has_full_access": true},
"quota": {"brands": 3, "audits_per_month": 10, "trend_history_days": 90},
"usage": {"brands": 2, "audits_this_month": 4, "audits_remaining": 6}
}
}
The full surface is 13 endpoints:
| Endpoint | What you get |
|---|---|
GET /account |
Subscription, quota, and usage |
GET /brands · GET /brands/{uuid} |
Brands with latest-audit and monitor summaries |
GET /audits |
Filterable by brand and status |
GET /audits/{uuid} |
Full audit with per-engine reports and recommendations |
GET /audits/{uuid}/reports |
Lightweight per-engine status, ideal for polling |
GET /monitors · GET /monitors/{uuid} |
Monitors with latest snapshot |
GET /monitors/{uuid}/competitors |
Tracked competitors |
GET /monitors/{uuid}/prompt-templates |
Standard and custom tracked queries |
GET /monitors/{uuid}/runs |
Individual AI answers with mentions, sentiment, citations |
GET /monitors/{uuid}/snapshots |
Weekly visibility snapshots, overall or per engine |
GET /monitors/{uuid}/trend |
Daily score series, clamped to your plan's history |
Lists use page-based pagination (?page=, ?per_page=, max 100) except the two high-volume feeds, runs and snapshots, which use cursors. Errors follow plain HTTP semantics: 401 for a bad key, 402 when a lapsed subscription blocks detail data, 422 for invalid query params, and 404 for a resource that's missing or belongs to someone else. That last one is deliberate: the API never confirms that another account's UUID exists.
The Laravel client
You can call all of that with any HTTP library. If your stack is Laravel, the official SDK saves you the boilerplate:
composer require a2zwebltd/brandgeo-laravel-client
Add the key to .env and you're connected:
BRANDGEO_API_KEY=1|xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
use A2ZWeb\BrandGeoClient\Facades\BrandGeo;
$account = BrandGeo::account()->get();
$account->subscription->status; // SubscriptionStatus::Active
$account->usage->auditsRemaining;
Everything comes back as readonly DTOs with string-backed enums and CarbonImmutable dates, so your IDE knows the shape of every response and a typo becomes a static-analysis error instead of a production surprise:
use A2ZWeb\BrandGeoClient\Enums\AuditStatus;
$audit = BrandGeo::audits()->list(status: AuditStatus::Done)->items[0];
$audit = BrandGeo::audits()->get($audit->uuid);
foreach ($audit->reports as $report) {
if ($report->isLocked()) {
continue; // trial paywall stub
}
$report->provider; // Provider::Openai, Anthropic, Gemini, Xai, DeepSeek
$report->normalizedScore; // 0–100
$report->grade; // A–F
}
Pagination is handled for you, including a lazy() bridge to Laravel collections for large result sets:
BrandGeo::monitors()->runs($uuid)
->lazy()
->take(500)
->filter(fn ($run) => $run->brandMentioned)
->each(fn ($run) => /* ... */);
$trend = BrandGeo::monitors()->trend($uuid, days: 90);
$trend->daysApplied; // clamped to your plan's history window
Each HTTP error maps to its own exception (AuthenticationException, SubscriptionRequiredException, RateLimitException with retryAfter, and so on), so error handling reads like intent instead of status-code checks. The client routes through Laravel's HTTP factory, which means Http::fake() works in your tests without any custom mocking.
One more method exists specifically for agencies managing keys for multiple client accounts:
foreach ($customers as $customer) {
$client = BrandGeo::withApiKey($customer->brandgeo_api_key);
$client->brands()->list();
}
withApiKey() returns an immutable clone, so the app-wide singleton never changes underneath you.
Getting started
The API is available now on every account. Generate a key at Settings → API, make your first GET /account call, and you have live data in under a minute. The full contract, including every field of every resource and a downloadable OpenAPI spec, lives at brandgeo.co/developers, and the client source is on GitHub.
If you build something on it, tell us; requests from API users decide which endpoints ship next.
See how AI describes your brand
BrandGEO runs structured prompts across ChatGPT, Claude, Gemini, Grok, and DeepSeek — and scores your brand across six dimensions. Two minutes, no credit card.