Frontpagely REST API
Read your AI-visibility data and manage the brands you track from your own code: tracked entities, measurement runs, SeenRate visibility snapshots, and webhooks. The API is part of the Pro plan.
Base URL
https://api.frontpagely.com/v1
Authentication
Create a key in the app under Settings → API, then send it as a Bearer token on every request:
curl https://api.frontpagely.com/v1/tracked_entities \
-H "Authorization: Bearer frontpagely_live_sk_…"
Keys belong to your team. There are three kinds:
- Secret keys (
…_sk_…) have full access to the team’s data. - Restricted keys (
…_rk_…) only have the scopes you give them:entities:read,entities:write,webhooks:read,webhooks:write. - Plugin keys (
…_pk_…) are minted by the WordPress plugin. They are read-only, bound to one tracked entity, and can only callGET /v1/widget.
Keys can optionally be limited to a list of IP addresses. When you rotate a key, the old one keeps working for a grace period and its responses carry Deprecation and Sunset headers.
Quickstart
# Create a tracked entity
curl https://api.frontpagely.com/v1/tracked_entities \
-H "Authorization: Bearer $FRONTPAGELY_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"name": "Acme Dental", "domain": "acmedental.com"}'
# List its measurement runs
curl "https://api.frontpagely.com/v1/runs?tracked_entity_id=ent_…" \
-H "Authorization: Bearer $FRONTPAGELY_KEY"
# Read its SeenRate history
curl "https://api.frontpagely.com/v1/visibility?tracked_entity_id=ent_…" \
-H "Authorization: Bearer $FRONTPAGELY_KEY"
Pagination
List endpoints return {"object": "list", "data": [...], "has_more": true|false}. Pass limit (1–100, default 25) and starting_after=<last id> to get the next page.
Rate limits
Per key: 100 read requests and 30 write requests per minute, with short bursts allowed. Responses carry X-RateLimit-Limit; a 429 carries Retry-After, X-RateLimit-Remaining and X-RateLimit-Reset. Every response has an X-Request-Id.
Errors
Errors use standard HTTP status codes and one JSON shape:
{
"error": {
"type": "invalid_request_error",
"code": "missing_required_field",
"message": "name is required.",
"param": "name",
"doc_url": "https://developers.frontpagely.com/errors/missing_required_field",
"request_id": "req_…"
}
}
See all error codes.
Webhooks
Register an endpoint with POST /v1/webhook_endpoints to get events as they happen: entity.created, entity.updated, entity.deleted, and webhook_endpoint.test. The signing secret is returned once, on create and on rotate.
Each delivery is a JSON POST with a Frontpagely-Signature header like t=1730000000,v1=<hex>. To verify it, compute HMAC-SHA256 of <t>.<raw body> with your signing secret and compare it to any v1 value (there are two during a secret rotation). Reject deliveries whose t is more than 5 minutes old.
// Node.js
import crypto from 'node:crypto';
function verify(header, rawBody, secret) {
const parts = header.split(',');
const t = parts.find(p => p.startsWith('t='))?.slice(2);
if (!t || Math.abs(Date.now() / 1000 - Number(t)) > 300) return false;
const expected = crypto.createHmac('sha256', secret).update(t + '.' + rawBody).digest('hex');
return parts.filter(p => p.startsWith('v1=')).some(p => p.slice(3) === expected);
}
Answer with any 2xx within 30 seconds. Failed deliveries are retried up to 10 times over about four days.
Reference
Every endpoint, parameter and field is in the API reference. The machine-readable contract is the OpenAPI 3.1 spec, which you can import into Postman, Insomnia or a code generator.
Questions about the API? Contact support, and include the request_id from any error.