Cheers Public API
The Cheers API allows you to programmatically access your organization's review data, badges, taps, and more. All API endpoints require authentication via API key.
https://app.cheers.tech/api/public/v1Authentication
All API requests require a Bearer token in the Authorization header. To obtain an API key, visit your organization settings or contact your Cheers account administrator.
curl -X GET "https://app.cheers.tech/api/public/v1/organizations?organization_id=123" \-H "Authorization: Bearer YOUR_API_KEY"
Rate Limits
Limits use a sliding 60-second window and are scoped by API key and endpoint. A request that passes the limiter consumes a slot even if later validation fails.
A limited request returns 429 Too Many Requests with Retry-After, X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset headers. Wait for Retry-After seconds, then retry the same request unchanged.
Common Parameters
Most endpoints support the following query parameters for filtering, pagination, and date-based queries.
Note: Either organization_id or parent_organization_id is required for initial scoped export requests; Map Pack accepts only organization_id. Reviews/taps cursor and checkpoint continuations must contain only that token.
Dataset and sync guide
Start with the dataset you need. A successful HTTP response or a returned row does not establish complete source coverage. All paths below are relative to /api/public/v1.
Choose the right organization
Use parent_organization_id equal to the organization that owns your API key to include its hierarchy, where the endpoint supports it. Use organization_id to select one allowed organization; it does not imply that organization's descendants. Send one selector. First paginate /organizations to build your ID mapping. For Map Pack, select LOCATION and SERVICE_AREA rows and request each ID separately; parent_organization_id is not supported. For Search, request the brand/property organization instead of assuming each location has separate GA4 or GSC data.
Freshness, partial rows and backfills
Google reporting can arrive or change after the observation date. Cheers also uses a configurable stable-data cutoff: the default GBP and GSC collection cutoff is five days behind, followed by each organization's scheduled refresh. This is a collection policy, not a guarantee that Google always takes five days. GA4 is collected independently. Check source observation timestamps and source-specific statuses, not just the latest successful fetch or the presence of a daily placeholder.
- Choose explicit observation dates and complete every page for that scope/window.
- Re-fetch an overlapping window daily and upsert by the keys above. A 14-day overlap is a useful starting point; expand it when an older gap or correction is reported. Source retention and access still bound what can be recovered. Export GET requests read stored observations; they do not trigger a new Google fetch.
- Keep partial rows and available fields. Null means unavailable or unobserved; zero is an observed value. Preserve availability metadata and source status alongside metrics.
- Check expected organizations and source-day coverage after the export. A complete cursor chain proves you retrieved the requested stored rows, not that every source observation exists. Record counts must use the same scope, dates, source and deletion/active filters to reconcile.
Endpoints
/organizationsRetrieve organization details.
Query Parameters
Response Fields
curl -X GET "https://app.cheers.tech/api/public/v1/organizations?organization_id=123" \-H "Authorization: Bearer YOUR_API_KEY"
[{"id": 123,"name": "Acme Restaurant","organization_type": "LOCATION","created_at": "2024-01-15T10:30:00Z","updated_at": "2024-06-20T14:45:00Z","billing_status": "PAID","plan_tier": "GROWTH","subscription_tier": "PAID","parent_organization_id": null}]
/location-linksMap each scoped business location to its configured Cheers survey URL and Trustpilot destination.
Query Parameters
Response Fields
A missing status reflects real configuration state; the API never fabricates a destination.
Every usable configured card and Trustpilot review destination is returned; oversized responses fail with 413 instead of being silently truncated.
The database derives and verifies the exact organization hierarchy for every request.
curl -X GET "https://app.cheers.tech/api/public/v1/location-links?parent_organization_id=123&state=TX" \-H "Authorization: Bearer YOUR_API_KEY"
[{"organization_id": 1300,"name": "Houston","city": "Houston","state": "TX","cheers_survey_urls": [{ "card_id": "550e8400-e29b-41d4-a716-446655440000", "url": "https://app.cheers.tech/api/v1/tap?card-id=550e8400-e29b-41d4-a716-446655440000&source=survey" }],"trustpilot_destinations": [{ "link_id": 101, "name": "Trustpilot", "url": "https://www.trustpilot.com/evaluate/example.com" }],"mapping_status": "ready"}]
/organization-connectionsRetrieve platform connections for organizations (Google, Yelp, Facebook, etc.).
Query Parameters
Response Fields
curl -X GET "https://app.cheers.tech/api/public/v1/organization-connections?organization_id=123" \-H "Authorization: Bearer YOUR_API_KEY"
[{"organization_id": 123,"google_place_id": "ChIJN1t_tDeuEmsRUsoyG83frY4","google_account_id": "accounts/123456789","google_location_id": "locations/987654321","yelp_business_id": "acme-restaurant-new-york","tripadvisor_location_id": null,"facebook_page_id": "123456789012345","facebook_url": "https://facebook.com/acmerestaurant","trustpilot_company_website": null,"bbb_profile_url": null,"created_at": "2024-01-15T10:30:00Z"}]
/cardsRetrieve badge/card information for your organization.
Query Parameters
Response Fields
curl -X GET "https://app.cheers.tech/api/public/v1/cards?organization_id=123" \-H "Authorization: Bearer YOUR_API_KEY"
[{"id": "550e8400-e29b-41d4-a716-446655440000","created_at": "2024-03-01T09:00:00Z","updated_at": "2024-03-15T14:30:00Z","cardholder_name": "John Smith","organization_id": 123,"title": "Server","photo_url": "https://storage.cheers.tech/photos/john-smith.jpg","encode_url": "https://app.cheers.tech/t/abc123","linktree_enabled": true,"badge_number": "EMP-001"}]
/cardsUpdate a card's organization assignment.
Request Body
Either cardId or badge_number is required in the request body.
Only cards already assigned to your organization or one of its descendants can be moved.
With cardId, a card already in the target organization returns {"id", "organization_id", "updated": false}.
With badge_number, every matching card you control is moved and the response is {"updated", "updated_count", "updated_ids", "target_organization_id"}.
curl -X PATCH "https://app.cheers.tech/api/public/v1/cards" \-H "Authorization: Bearer YOUR_API_KEY" \-H "Content-Type: application/json" \-d '{"cardId": "550e8400-e29b-41d4-a716-446655440000", "organization_id": 456}'
{"id": "550e8400-e29b-41d4-a716-446655440000","organization_id": 456,"updated_at": "2026-10-02T12:00:00.000Z"}
/tapsRetrieve tap events (when a customer taps a badge). Agent-scoped taps are attributed to the resolved destination organization.
Query Parameters
Response Fields
For an agent-scoped URL, Cheers resolves and validates destination before inserting the tap. The tap keeps the agent card_id and stores the destination organization_id.
The tap organization is the source of truth for the rest of the link-tree journey; downstream link interactions reuse it.
curl -X GET "https://app.cheers.tech/api/public/v1/taps?organization_id=123&from=2024-01-01T00:00:00Z" \-H "Authorization: Bearer YOUR_API_KEY"
[{"id": 12345,"created_at": "2024-06-15T18:30:00Z","updated_at": "2024-06-15T18:30:00Z","card_id": "550e8400-e29b-41d4-a716-446655440000","organization_id": 123,"source": "badge","used": true}]
/reviewsRetrieve customer reviews from all connected platforms. Agent attribution is retained when Cheers can match the review to a recorded journey.
Query Parameters
Response Fields
Use format=v2 to get all available fields including source and reviewer information.
Reviews with not_showing=true are retained for API history but hidden from Cheers review counts and views.
not_showing_at is the time Cheers detected the review was no longer showing on the source platform, not necessarily the exact platform deletion time.
from and to filters include the time Cheers first ingested a review and include not_showing_at for reviews where not_showing=true, so rolling syncs recover late arrivals and deletion visibility changes.
The ingestion timestamp is not exported; clients must trust the server-side activity-window decision instead of re-filtering returned rows by visible timestamps.
This export preserves canonical provider organization ownership. For agent-by-destination reporting use GET /employee-links/reviews, which requires persisted journey evidence and does not promise DMA-level attribution for unmatched shared-profile reviews.
curl -X GET "https://app.cheers.tech/api/public/v1/reviews?organization_id=123&format=v2" \-H "Authorization: Bearer YOUR_API_KEY"
[{"id": 5678,"created_at": "2024-06-10T12:00:00Z","updated_at": "2024-06-10T12:00:00Z","rating": 5,"card_id": "550e8400-e29b-41d4-a716-446655440000","review_text": "Amazing service! John was incredibly helpful.","organization_id": 123,"source": "GOOGLE","reviewer_name": "Jane D.","reviewer_photo_url": "https://lh3.googleusercontent.com/...","owner_response": "Thank you for the kind words!","response_timestamp": "2024-06-11T09:00:00Z","review_url": "https://search.google.com/local/reviews?...","internal": false,"not_showing": false,"not_showing_at": null}]
/linksRetrieve review links configured for your organization.
Query Parameters
Response Fields
curl -X GET "https://app.cheers.tech/api/public/v1/links?organization_id=123" \-H "Authorization: Bearer YOUR_API_KEY"
[{"id": 101,"created_at": "2024-02-01T10:00:00Z","updated_at": "2024-02-01T10:00:00Z","url": "https://search.google.com/local/writereview?placeid=ChIJN1t_tDeuEmsRUsoyG83frY4","organization_id": 123,"name": "Leave a Google Review","subtitle": "Leave a review","sms_template": null,"is_verify": false}]
/link_interactionsRetrieve link click/interaction events. Agent-scoped link-tree interactions reuse the organization saved on the originating tap.
Query Parameters
Response Fields
curl -X GET "https://app.cheers.tech/api/public/v1/link_interactions?organization_id=123" \-H "Authorization: Bearer YOUR_API_KEY"
[{"id": 9876,"link_id": 101,"card_id": "550e8400-e29b-41d4-a716-446655440000","created_at": "2024-06-15T18:31:00Z","updated_at": "2024-06-15T18:31:00Z","used": true,"organization_id": 123}]
/employee-linksCreate or update one employee review link, or provision up to 1,000 links with an items array. One case-insensitive agent_id maps to one root employee; agent scope reuses one active card across DMA/brand destinations.
Request Body
Response Fields
Repeated requests with the same case-insensitive agent_id reuse one root employee. Agent scope creates or reuses one active card owned by the tenant-root organization, regardless of how many DMA/brand destinations are used.
card_scope defaults to location, so existing integrations and cards keep their current behavior. Agent scope is opt-in and never converts or updates a location-scoped card.
In agent scope, organization_id is the initial active non-ADMIN DMA/brand organization. Cheers returns its numeric ID as destination and uses it to select that organization's link tree; no destination code is decoded, generated, or stored as a separate routing record.
Agent destinations must have an explicit BRAND, LOCATION, DEPARTMENT, or SERVICE_AREA type, and the card root must be an active ADMIN organization. Untyped organizations are rejected before provisioning.
Store base_url once per agent. For each survey, set destination to the mapped organization_id and source=survey. The complete URL can be rebuilt without another provisioning call.
Use the returned base_url, not a manually constructed legacy /api/v1/tap URL. Dedicated /api/agent/v1 and /agent/v1 routes stop agent journeys on pre-agent releases during rollback; existing location-card URLs are unchanged.
Employee lookup, batch grouping, and uniqueness use the database lower(btrim(...)) normalization, including Unicode. Preserve the original agent_id rather than implementing client-side case folding.
Cheers validates destination before inserting the tap. Link-tree interactions reuse the organization saved on that tap, so tap and link-interaction exports retain DMA/brand attribution while keeping the agent card_id.
Store the returned base_url, not a redirected URL containing tap. Cheers creates a fresh saved journey at entry; profile, contact, preview and tracking follow-ups must match that card and destination and expire after 24 hours. To select another destination or restart an expired journey, open base_url with the intended destination again. Disabled agent cards or link trees reject follow-ups.
Reviews are attributed to an agent and destination organization only when Cheers can match the review to journey evidence. A shared platform profile without deterministic evidence cannot promise DMA-level review attribution.
Batch responses preserve input order. Full success returns 200; partial failure returns 207 with per-item status values. Successful items remain committed and are safe to retry.
Repeated agent_id values in one batch must use identical employee metadata, while organization_id may differ to produce destination-specific URLs for the same card.
Bulk processing preserves input order and processes repeated case-insensitive agent_id values sequentially, including across card scopes and destinations. Different agents run with at most 10 items in flight. Send at most 1,000 items and 100 link writes per batch; each item reports its own status and failure. A batch over the write budget returns 400 batch_work_limit_exceeded before any write; it still uses one bulk rate-limit slot, so split batches by the write budget before sending.
For card_scope agent, the agent card does not depend on the destination: the first item for an agent writes it, and later destinations for that agent in the same batch are validated and answered without another write. For an initial sync, one item per agent is enough; build each destination URL from base_url by appending &destination=<organization_id>. Destinations are validated when the link is opened: an organization outside the agent's tenant, inactive, or of an unsupported type shows the inactive-link page instead of redirecting.
If an agent-scope agent's employee or card write fails twice in one batch, its remaining destinations in that batch return the same error without another write attempt. Successful items stay committed, and retrying the failed items or the unchanged request is safe.
API-provisioned cards are digital-only and never enter the physical badge print queue.
The API key must belong to the root organization, and organization_id must be an active non-ADMIN organization within that tenant.
Archived agents are never reactivated as a side effect; send reactivate: true to bring one back.
curl -X POST "https://app.cheers.tech/api/public/v1/employee-links" \-H "Authorization: Bearer YOUR_API_KEY" \-H "Content-Type: application/json" \-d '{"organization_id": 456,"agent_id": "AGENT-0042","first_name": "Ada","last_name": "Lovelace","destination_mode": "linktree"}'
{"employee_id": "8b194ed6-88a0-4f42-a280-d63ea47b5718","card_id": "550e8400-e29b-41d4-a716-446655440000","organization_id": 456,"agent_id": "AGENT-0042","destination_mode": "linktree","review_link_id": null,"url": "https://app.cheers.tech/api/v1/tap?card-id=550e8400-e29b-41d4-a716-446655440000","landing_page_url": "https://app.cheers.tech/urltree?id=550e8400-e29b-41d4-a716-446655440000","created_employee": true,"created_link": true}
One stable card per agent with a DMA/brand destination
curl -X POST "https://app.cheers.tech/api/public/v1/employee-links" \-H "Authorization: Bearer YOUR_API_KEY" \-H "Content-Type: application/json" \-d '{"organization_id": 456,"agent_id": "AGENT-0042","first_name": "Ada","last_name": "Lovelace","card_scope": "agent","destination_mode": "linktree"}'
{"employee_id": "8b194ed6-88a0-4f42-a280-d63ea47b5718","card_id": "550e8400-e29b-41d4-a716-446655440000","organization_id": 456,"card_organization_id": 123,"agent_id": "AGENT-0042","card_scope": "agent","destination_mode": "linktree","destination": 456,"base_url": "https://app.cheers.tech/api/agent/v1/tap?card-id=550e8400-e29b-41d4-a716-446655440000","review_link_id": null,"url": "https://app.cheers.tech/api/agent/v1/tap?card-id=550e8400-e29b-41d4-a716-446655440000&destination=456","landing_page_url": "https://app.cheers.tech/agent/v1?id=550e8400-e29b-41d4-a716-446655440000&destination=456","created_employee": false,"created_link": true}
Batch (up to 1,000 links)
curl -X POST "https://app.cheers.tech/api/public/v1/employee-links" \-H "Authorization: Bearer YOUR_API_KEY" \-H "Content-Type: application/json" \-d '{"items": [{"organization_id": 456,"agent_id": "AGENT-0042","first_name": "Ada","last_name": "Lovelace","card_scope": "agent","destination_mode": "linktree"},{"organization_id": 789,"agent_id": "AGENT-0042","first_name": "Ada","last_name": "Lovelace","card_scope": "agent","destination_mode": "linktree"}]}'
{"requested": 2,"succeeded": 2,"failed": 0,"created_employee_count": 1,"created_link_count": 1,"results": [{ "index": 0, "status": 201, "employee_id": "8b194ed6-88a0-4f42-a280-d63ea47b5718", "card_id": "550e8400-e29b-41d4-a716-446655440000", "destination": 456, "url": "https://app.cheers.tech/api/agent/v1/tap?card-id=550e8400-e29b-41d4-a716-446655440000&destination=456" },{ "index": 1, "status": 200, "employee_id": "8b194ed6-88a0-4f42-a280-d63ea47b5718", "card_id": "550e8400-e29b-41d4-a716-446655440000", "destination": 789, "url": "https://app.cheers.tech/api/agent/v1/tap?card-id=550e8400-e29b-41d4-a716-446655440000&destination=789" }]}
/employee-links/reviewsRetrieve reviews attributed to one agent card at one destination organization using persisted journey evidence. Canonical provider ownership stays unchanged. This is attribution evidence, not a guarantee that a click caused a review.
Query Parameters
Response Fields
100 requests per API key per 60 seconds. Requires agent mode; existing /reviews remains the canonical provider-organization export.
For tap and link-interaction metrics, use the existing organization-scoped exports and group by the same card_id. Review attribution is not verified conversion identity.
curl "https://app.cheers.tech/api/public/v1/employee-links/reviews?card_id=550e8400-e29b-41d4-a716-446655440000&organization_id=456" -H "Authorization: Bearer YOUR_API_KEY"
{"card_id": "550e8400-e29b-41d4-a716-446655440000","organization_id": 456,"reviews": [],"total": 0,"limit": 100,"offset": 0,"lifetime_earned_review_count": 0,"attribution_basis": "persisted_destination_evidence"}
/employee-linksTerminate one agent or deactivate up to 100 agents. Deactivation is a soft delete: matching cards are marked inactive, and an employee is archived only for an unscoped termination. The endpoint is idempotent and repeating a request returns zero newly deactivated links.
Request Body
Response Fields
A deactivated link stops resolving; visitors who follow it see the inactive-link page instead of a review destination.
Deletion is soft: employees, cards, links, taps, interactions, reviews, and attribution history are retained; only is_active flags change.
Historical taps and reviews stay attributed to the agent after termination.
If employee archival fails after cards were deactivated, the failed item's result includes those card IDs/counts and employee_archived: false. Retry to finish archival; the bulk total includes known deactivations from partial failures.
DELETE organization_id scopes card ownership, not destination routing. Pass the returned card_organization_id (root for agent scope) to disable root-owned agent cards while preserving the employee and child-location cards. Omit it only for whole-employee termination. A child DMA ID cannot revoke one destination from a shared root card.
An unknown agent_id returns 404 employee_not_found; an organization_id outside the tenant returns 403.
Bulk items accept only agent_id and optional organization_id. A provided null or empty organization_id, an unknown item field, or top-level/query selectors mixed with items is rejected before any write.
All bulk item shapes and organization authorization are validated before writes. Same case-insensitive agent_id items run sequentially in input order; different agents run with a maximum of 10 in flight.
Bulk responses preserve input order. Full success returns 200; any item failure returns 207 Multi-Status. Successful items remain committed, so retry failed indexes when possible or safely retry the unchanged request.
The bulk deactivated_link_count is the sum of per-item counts and counts only cards newly marked inactive. An employee is archived only by an unscoped item.
The standard 500-request bucket is shared by single POST and DELETE calls; bulk POST and DELETE share the 10-batch-request bucket and each bulk request also consumes one standard slot.
curl -X DELETE "https://app.cheers.tech/api/public/v1/employee-links" \-H "Authorization: Bearer YOUR_API_KEY" \-H "Content-Type: application/json" \-d '{ "agent_id": "AGENT-0042" }'
{"employee_id": "8b194ed6-88a0-4f42-a280-d63ea47b5718","agent_id": "AGENT-0042","organization_id": null,"employee_archived": true,"deactivated_link_count": 1,"deactivated_card_ids": ["550e8400-e29b-41d4-a716-446655440000"]}
Bulk soft delete (up to 100 agents)
curl -X DELETE "https://app.cheers.tech/api/public/v1/employee-links" \-H "Authorization: Bearer YOUR_API_KEY" \-H "Content-Type: application/json" \-d '{"items": [{ "agent_id": "AGENT-0042", "organization_id": 456 },{ "agent_id": "AGENT-0043" },{ "agent_id": "AGENT-0042", "organization_id": 789 }]}'
{"requested": 3,"succeeded": 2,"failed": 1,"deactivated_link_count": 2,"results": [{ "index": 0, "status": 200, "agent_id": "AGENT-0042", "organization_id": 456, "deactivated_link_count": 1, "deactivated_card_ids": ["550e8400-e29b-41d4-a716-446655440000"] },{ "index": 1, "status": 404, "agent_id": "AGENT-0043", "error": "employee_not_found" },{ "index": 2, "status": 200, "agent_id": "AGENT-0042", "organization_id": 789, "deactivated_link_count": 1, "deactivated_card_ids": ["660e8400-e29b-41d4-a716-446655440000"] }]}
/gbp-performanceRetrieve daily Google Business Profile Search, Maps, and customer-action metrics by location.
Query Parameters
Response Fields
Missing observations are returned as unavailable with null metrics, never as misleading zeroes.
Google reports each metric on its own delay (Search impressions up to about 10 days). Metrics after Google's latest reported day are null with availability_reason not_yet_reported_by_google; request a range ending earlier for complete totals.
curl -X GET "https://app.cheers.tech/api/public/v1/gbp-performance?parent_organization_id=123&from=2026-08-01&to=2026-08-07&limit=500" \-H "Authorization: Bearer YOUR_API_KEY"
[{"organization_id": 456,"date": "2026-08-01","data_status": "complete","search_views": 320,"maps_views": 184,"website_clicks": 12,"phone_calls": 8,"direction_requests": 5,"total_actions": 25,"bookings": 2,"last_updated_at": "2026-08-02T12:00:00.000Z"}]
/search-performanceRetrieve daily Google Search Console, Google Analytics, referral, and Cheers Search Visibility metrics by organization.
Query Parameters
Response Fields
GSC and GA4 facts belong to the organization with the connected property, commonly a BRAND. Other organization/date rows may be placeholders; totals are not automatically attributed to individual locations.
A row is complete only when both GSC and GA4 observations exist. Missing source metrics stay null.
Use X-Total-Count, X-Limit, and X-Offset for pagination.
curl -X GET "https://app.cheers.tech/api/public/v1/search-performance?parent_organization_id=123&from=2026-08-01&to=2026-08-07&limit=500" \-H "Authorization: Bearer YOUR_API_KEY"
[{"organization_id": 456,"date": "2026-08-01","data_status": "complete","search_impressions": 950,"search_clicks": 74,"search_ctr": 0.0779,"average_search_position": 6.4,"sessions": 410,"organic_sessions": 220,"referral_sessions": 31,"search_visibility_score": 72,"last_updated_at": "2026-08-04T12:00:00.000Z"}]
/search-keywordsRetrieve daily Google Search Console query metrics by organization.
Query Parameters
Response Fields
The legacy coverage suffix per_location refers to the returned organization_id, which may be a BRAND; it does not imply organization_type=LOCATION.
Query rows are a top-500 per-organization/day diagnostic dimension and must not be summed as property totals.
Each request is limited to a 31-day window.
Advance offset by X-Limit while X-Has-More is true.
curl -X GET "https://app.cheers.tech/api/public/v1/search-keywords?parent_organization_id=123&from=2026-08-01&to=2026-08-07&limit=500" \-H "Authorization: Bearer YOUR_API_KEY"
[{"organization_id": 456,"date": "2026-08-01","query": "best electricity provider","impressions": 85,"clicks": 7,"search_ctr": 0.0824,"average_search_position": 5.2,"coverage": "daily_top_500_queries_by_impressions_per_location"}]
/website-optimization-scoresRetrieve Website Optimization audit state and versioned site scores.
Query Parameters
Response Fields
Queued, failed, blocked, or unscored audits retain null scores; zero is never substituted.
Compare score movement only when the score_model_version supports that comparison.
Advance offset by X-Limit while X-Has-More is true.
curl -X GET "https://app.cheers.tech/api/public/v1/website-optimization-scores?parent_organization_id=123&from=2026-07-01&to=2026-08-31" \-H "Authorization: Bearer YOUR_API_KEY"
[{"audit_run_id": "550e8400-e29b-41d4-a716-446655440000","organization_id": 456,"week_start": "2026-08-17","data_status": "complete","overall_score": 82,"schema_score": 70,"ai_readiness_score": 88,"content_score": 80,"performance_score": 76,"crawlability_score": 91,"score_model_version": 15}]
/map-pack-rankingsRetrieve every grid-point rank observation from completed Google Local Finder runs.
Query Parameters
Response Fields
The supported default grid expects 25 rows. A partial completed run can contain fewer; inspect run_data_status and the grid-point counts.
A null business_rank means not found in the observed results, not rank zero.
Points whose provider result was unusable (an out-of-market list, or unverifiable listing identity) are omitted and counted in grid_points_invalid.
Raw provider result payloads are not exposed.
Enumerate locations with /organizations, then export one location at a time in windows of at most 31 days.
Follow X-Next-Cursor while X-Has-More is true; nonzero offsets are rejected.
curl -X GET "https://app.cheers.tech/api/public/v1/map-pack-rankings?organization_id=456&from=2026-08-01&to=2026-08-07&limit=500" \-H "Authorization: Bearer YOUR_API_KEY"
[{"organization_id": 456,"keyword": "electric company","run_id": "0787d09e-89a3-4dab-ac2a-cb7927d30aa2","grid_generation": 3,"grid_row": 0,"grid_col": 0,"latitude": 29.7604,"longitude": -95.3698,"business_rank": 7,"rank_status": "ranked","ranking_method": "organic","run_data_status": "complete","grid_points_expected": 25,"grid_points_succeeded": 25,"grid_points_failed": 0,"grid_points_invalid": 0}]
/ai-visibilityRetrieve daily brand appearance, rank, and citation metrics by location, prompt, and AI platform, and optionally for brand-wide prompts that are not tied to a location.
Query Parameters
Response Fields
organization_id returns one organization only. A brand or root organization owns no location rows, so organization_id=<root> with the default scope is an empty 200 with an X-Warning header that names the request to use instead. For every location, use parent_organization_id=<root>; add scope=all to include brand-wide prompts.
scope defaults to location, so existing integrations keep the same rows. scope=brand adds brand-wide prompts, measured once for the brand. scope=all returns both without double counting: a location prompt is only ever returned as location rows, never as a brand total.
Four or more valid observations are complete, one to three are partial, and zero is unavailable.
Most prompts run once per platform per day, so one daily row usually has runs: 1 and data_status: partial. Partial means thin evidence in that row, not failed collection. For a complete reading, sum runs and appearances over several days (for example a week) and compare the sum of runs with minimum_complete_runs.
minimum_complete_runs is a quality threshold, not the tracked prompt's scheduling cadence.
Unavailable performance fields are null; zero in a partial or complete row is an observed zero.
Rank and written-answer appearances are separate: a map/place listing can supply a rank even when appearances is zero. The existing avg_rank_when_present field name does not mean the average is filtered to written-answer appearances.
rank_samples counts recorded ranks, not runs or appearances. A known zero remains zero even when runs is zero; an unknown legacy count remains null. Neither a zero count nor a null rank proves that the business was absent or that the platform cannot supply rankings.
data_status describes run coverage, not rank coverage. For a combined rank across compatible rows, weight each non-null avg_rank_when_present by its positive rank_samples count; do not average the row averages equally or replace missing ranks with zero.
Use the X-Next-Cursor response header for scalable pagination; nonzero offsets are rejected. Keep the same scope, organization, dates and limit on every page of one export.
A 503 with a Retry-After header means the query timed out under load after one automatic retry. Wait Retry-After seconds and repeat the same request, with the same cursor.
curl -X GET "https://app.cheers.tech/api/public/v1/ai-visibility?parent_organization_id=123&scope=all&from=2026-08-01&to=2026-08-07&limit=1000" \-H "Authorization: Bearer YOUR_API_KEY"
[{"brand_id": 123,"brand_name": "Example Energy","location_id": 456,"location_name": "Houston","organization_id": 456,"scope": "location","date": "2026-08-01","ai_prompt_id": "9018cc4f-5170-42b3-9bfd-493d91bf2f81","ai_prompt": "best electricity provider in Houston","ai_platform_id": "2c53a16e-013b-4c63-8afc-805f1fa4d9ce","ai_platform": "ChatGPT","data_status": "complete","runs": 20,"minimum_complete_runs": 4,"appearances": 12,"appearance_rate_pct": 60,"avg_rank_when_present": null,"rank_samples": 0,"citations": 7,"citation_rate_pct": 35,"last_updated_at": "2026-08-02T12:00:00.000Z"},{"brand_id": 123,"brand_name": "Example Energy","location_id": null,"location_name": null,"organization_id": 123,"scope": "brand","date": "2026-08-01","ai_prompt_id": "5b0d3c1e-8f7a-4f45-9a51-2f3f8c0f6d11","ai_prompt": "Is Example Energy legit?","ai_platform_id": "2c53a16e-013b-4c63-8afc-805f1fa4d9ce","ai_platform": "ChatGPT","data_status": "partial","runs": 1,"minimum_complete_runs": 4,"appearances": 1,"appearance_rate_pct": 100,"avg_rank_when_present": null,"rank_samples": 0,"citations": 1,"citation_rate_pct": 100,"last_updated_at": "2026-08-02T09:10:00.000Z"}]
Error Handling
All endpoints return consistent error responses with appropriate HTTP status codes.
{"error": "Error message describing the issue"}
Pagination
Pagination differs by endpoint. Always send your Bearer key, URL-encode tokens, and retain the same scope and date filters unless using a token-only snapshot continuation. Respect HTTP 429 Retry-After; do not mark a failed or incomplete export as complete.
Offset exports
Advance offset by the requested page limit (or X-Limit when provided). For organizations, GBP and Search performance, stop when the next offset reaches X-Total-Count. For search keywords and website scores, follow X-Has-More. Cards, links and link interactions have no total-count header: continue until a short or empty page. Stable ordering is not a snapshot under concurrent changes; use overlapping syncs and periodic reconciliation.
GET /search-performance?parent_organization_id=123&from=2026-09-01&to=2026-09-07&limit=100&offset=0GET /search-performance?parent_organization_id=123&from=2026-09-01&to=2026-09-07&limit=100&offset=100
AI visibility and Map Pack cursors
Keep the original organization, dates and limit on every request; add X-Next-Cursor as the cursor parameter. Map Pack uses X-Has-More and X-Next-Cursor. AI visibility ends when no X-Next-Cursor is returned; an exact-size final page may require one extra empty request. Do not reuse a cursor across locations or date windows. These are observation cursors, not saved incremental checkpoints.
GET /map-pack-rankings?organization_id=456&from=2026-09-01&to=2026-09-07&limit=999GET /map-pack-rankings?organization_id=456&from=2026-09-01&to=2026-09-07&limit=999&cursor=URL_ENCODED_TOKENGET /ai-visibility?parent_organization_id=123&from=2026-09-01&to=2026-09-07&limit=1000GET /ai-visibility?parent_organization_id=123&from=2026-09-01&to=2026-09-07&limit=1000&cursor=URL_ENCODED_TOKEN
Reviews and taps snapshots
For taps and reviews, omit offset to use immutable cursor pagination. Follow the X-Next-Cursor header until X-Has-More is false, then save the final X-Checkpoint for the next incremental run.
# Start an immutable export (1-999 rows per page)GET /reviews?parent_organization_id=123&format=v2&limit=500# Continue the same session; send no other query parametersGET /reviews?cursor=VALUE_FROM_X_NEXT_CURSOR# Start the next incremental run after the prior final page commitsGET /reviews?checkpoint=VALUE_FROM_X_CHECKPOINT
Cursor sessions expire after six hours; metadata-only checkpoints expire after seven days. Upsert by record ID and only advance a checkpoint after every page succeeds. Explicit offset is legacy compatibility mode.
Filtering by Date
Daily reporting endpoints use inclusive observation dates (YYYY-MM-DD); website scores filter audit week_start. Their last_updated_at field is metadata, not an updated-since filter. Entity exports use ISO 8601 timestamps for activity/updated and created filters. Reviews include late ingestion and deletion-detection activity, so do not re-filter returned reviews solely by their visible created_at or updated_at values:
# Reviews updated in the last 7 daysGET /reviews?organization_id=123&from=2024-06-08T00:00:00Z# Reviews created in January 2024GET /reviews?organization_id=123&created_from=2024-01-01T00:00:00Z&created_to=2024-01-31T23:59:59Z
Need Help?
For API support, contact us at info@cheers.tech