MetricsGo API & MCP
Read access to the Meta ads and organic social data MetricsGo has synced for your organisation — from your own dashboards and backends (REST) or from Claude, Cursor and agents (MCP).
- REST base URL:
https://metricsgo.srv1821420.hstgr.cloud/api/v1 - MCP endpoint:
https://metricsgo.srv1821420.hstgr.cloud/api/mcp - API reference: /docs/api/reference · OpenAPI document:
GET /api/v1/openapi.json(no auth) - Field definitions: data-contract.md, also served by the
describe_metricsMCP tool
Keys
An organisation admin creates keys under Settings → API & MCP. A key:
- is shown once — MetricsGo stores a hash, not the key; lose it and you revoke it and create another
- belongs to the organisation, not the person who made it; it keeps working after they leave — revoke it there
- carries scopes (
ads:read,social:read) that gate endpoints, and an optional client list that gates rows; neither can widen the other - looks like
mg_live_followed by 43 characters
Send it as a bearer token on every request:
Authorization: Bearer mg_live_…
Never in a query string, cookie or body — those are rejected, and a key in a URL is a key in someone's logs.
Keys stay on the server
The API sends no CORS headers, deliberately. A key in browser JavaScript is a key handed to every visitor of that page. Your dashboard calls your backend; your backend calls MetricsGo.
Endpoints
All GET. Dates are YYYY-MM-DD calendar days in Asia/Kolkata; a range may not exceed 366 days.
| Endpoint | Scope | Query |
|---|---|---|
/v1/me |
any | — |
/v1/clients |
any | — |
/v1/ads/overview |
ads:read |
from to client? campaignId? adSetId? adId? |
/v1/ads/entities |
ads:read |
level=campaign|adset|ad from to client? search? |
/v1/ads/breakdowns |
ads:read |
level entityId from to |
/v1/social/overview |
social:read |
from to client? |
/v1/social/posts |
social:read |
from to client? limit? (1–500, default 100) |
/v1/social/thumbnail |
social:read |
post |
client is a client id from /v1/clients. entityId is the entity's Meta platform id (as shown in Ads Manager) or its id from /v1/ads/entities.
Which client does a row belong to?
Every row from /v1/ads/entities — and every campaign in /v1/ads/overview — carries its lineage, the same join keys Meta puts on its own objects (account_id, campaign_id, adset_id) plus the names:
{
"id": "…", "platformId": "120251864157900220", "name": "Paid Webinar Sales Campaign_Aug12",
"account": { "id": "…", "platformAccountId": "act_714689862204894", "name": "Sheizen Wellness" },
"client": { "id": "…", "name": "Sheizen Wellness" },
"campaign": null,
"adSet": null
}
clientis how a row is attributed to a client. An account that is not assigned to a client still gets a name — the account's own — withclient.idnull, so grouping byclient.namealways works.campaignis set on ad-set and ad rows;adSetis set on ad rows.platformIdinside them is the Meta id, so you can join to anything you already pull from Meta.- To pipe data per client, either call with
client=<id>(one client per call) or call once without it and group byclient.id.
Response envelope
{
"data": { … },
"meta": {
"timezone": "Asia/Kolkata",
"from": "2026-08-25",
"to": "2026-08-31",
"syncedAt": "2026-09-06T07:30:58.194Z",
"currency": "INR",
"truncated": false
}
}
meta.syncedAt is always present: every number is stored data synced by MetricsGo. The API never calls Meta on your behalf, so a request never spends your Meta quota — and never returns anything fresher than the last sync.
Lists are capped at 500 rows. truncated: true means the cap applied; narrow the range or filter by client.
Errors
RFC 9457 application/problem+json:
{
"type": "https://app.digygo.com/docs/api/errors#rate_limited",
"title": "Too Many Requests",
"status": 429,
"detail": "TooManyRequests: 60 requests per minute per key",
"code": "rate_limited"
}
| Status | code |
When |
|---|---|---|
| 400 | validation_failed |
bad query (errors[] lists each problem) |
| 401 | unauthorized |
missing, malformed, unknown, revoked or expired key |
| 403 | forbidden |
key lacks the endpoint's scope |
| 404 | not_found |
client or entity outside the key's reach (existence is never confirmed) |
| 429 | rate_limited |
over 60 requests/minute for this key — honour Retry-After |
| 503 | unavailable |
transient; retry after Retry-After |
Rate limits
60 requests per minute per key, exact. Every response carries X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset (unix seconds); a 429 adds Retry-After.
Freshness
Ads data syncs hourly (last 3 days re-pulled nightly, 28 days weekly, because Meta restates). Social syncs on the same schedule. Breakdowns are fetched on demand by the dashboard; the API serves the cache and sets stale: true when the dashboard would have refetched.
MCP
The MCP server exposes seven read-only tools: list_clients, get_ads_overview, list_ad_entities, get_ad_breakdowns, get_social_overview, list_social_posts, describe_metrics. They return the same { data, meta } envelope as REST, validated by the same schemas.
Claude Code — one command:
claude mcp add --transport http metricsgo "https://metricsgo.srv1821420.hstgr.cloud/api/mcp" --header "Authorization: Bearer <key>"
Cursor and other MCP clients — mcp.json:
{ "mcpServers": { "metricsgo": { "url": "https://metricsgo.srv1821420.hstgr.cloud/api/mcp", "headers": { "Authorization": "Bearer <key>" } } } }
Claude.ai, Claude Desktop and ChatGPT — no key needed. Add the connector with the MCP URL and click Connect: the client discovers MetricsGo's OAuth server (/.well-known/oauth-protected-resource/api/mcp → /.well-known/oauth-authorization-server), sends you to sign in, and you approve it on a consent screen naming the app, the permissions and the organisation. The approval appears in Settings → API & MCP as a connected app and can be revoked there. Grants see exactly the clients the approving user can see. Organisations with Claude's "Request headers" beta can still use a key (Authorization: Bearer <key>).
OAuth 2.1 details (for client authors)
- Authorization code + PKCE (S256 required),
resource=https://metricsgo.srv1821420.hstgr.cloud/api/mcp(RFC 8707), tokens are audience-bound to the MCP endpoint and rejected on/api/v1. - Client identification: Client ID Metadata Documents (
client_id= your https metadata URL) or dynamic registration atPOST /oauth/register. Redirect URIs must be https or loopback (http://localhost/127.0.0.1, any port). - Endpoints:
/oauth/authorize,/oauth/token(form-urlencoded;authorization_code,refresh_token),/oauth/revoke(RFC 7009). - Access tokens last 1 hour; refresh tokens 30 days and rotate on every use. Reusing a rotated refresh token revokes the grant.
- Scopes:
ads:read,social:read(default: both). Scope may narrow on refresh, never widen.
Tip: ask the model to call describe_metrics first. It explains that null means "not reported by the platform" and is never a zero — the most common misreading of this data.
Compliance
You may process this data only on behalf of the business that connected the Meta account, and only for that business. Do not sell, license, aggregate across businesses, or use it to build or augment profiles of individuals (Meta Platform Terms §5).
