API

Heading API reference

Read-only REST API for Heading. Every endpoint is GET, and only paid properties return data.

Programmatic access to properties, prompts, visibility, AI responses, competitors, sources, and tasks. Authenticate with API keys. Get JSON responses.

Two limits before you start. The API is read-only: every endpoint is GET, and no write endpoints have shipped yet. It covers paid properties only: free properties do not appear in any endpoint, including /v1/properties.

Base URL

https://api.useheading.com/v1

OpenAPI specification

The same surface, written for a program:

https://api.useheading.com/openapi.json

OpenAPI 3.1, served with permissive CORS so a browser-based client can read it. Every endpoint documented on this site has an operation in it, with a unique operationId, typed parameters and a response schema. A test walks the route handlers and fails when an endpoint appears in one place and not the others, so the specification, these pages and the running API cannot drift apart.

Authentication

All requests require an API key passed as a Bearer token in the Authorization header.

Create API keys from Settings > API in the Heading dashboard. Keys use the hdg_sk_live_ prefix.

curl https://api.useheading.com/v1/properties \
  -H "Authorization: Bearer hdg_sk_live_abc123..."

API keys are shown once at creation and cannot be retrieved later. Store them securely.

Access levels

Both key access levels are accepted, because there is nothing to write yet:

LevelPermissions
ReadGET requests
WriteGET requests. Reserved for upcoming write endpoints. Grants nothing extra today.

Data access

The API returns data for properties on a paid plan (Starter, Growth, or Scale). Free properties do not appear in any endpoint, including /v1/properties.

Property scoping

Keys can be scoped to specific properties or granted access to all properties on the team. Scoped keys only return data for their allowed properties. Filtering by a propertyId outside the key's scope returns an empty list, not an error.

Resources

Pagination

List endpoints accept limit and offset:

  • limit: integer. Maximum results per page. Default: 100, max: 1000.
  • offset: integer. Rows to skip. Default: 0.

total in the response is the full match count, independent of pagination. There is no cursor and no next link, and there is no batch or bulk endpoint: fetching a lot of data means paging these list endpoints.

Date ranges

Time-series endpoints (/v1/visibility, /v1/responses, /v1/sources, /v1/sources/urls) accept from and to as UTC calendar days (yyyy-MM-dd). Both bounds are inclusive. Omitting both gives the last 30 UTC days, ending today. Omitting from alone starts the range 29 days before to, so it is 30 UTC days counting both ends. All dates in responses are UTC.

Response format

All responses return JSON with a consistent structure.

Success: list

{
  "data": [...],
  "total": 5
}

Success: detail

{
  "data": { ... }
}

Error

{
  "error": {
    "code": "MISSING_AUTH",
    "message": "Authorization header is required"
  }
}

Every error uses this envelope, including 429, a request to a path under /v1 that does not exist, and a method other than GET on a path that does exist. The API never answers an HTML error page.

Methods

Every endpoint serves GET, HEAD and OPTIONS, and nothing else. HEAD returns the headers of the GET; OPTIONS answers 204 with Allow: GET, HEAD, OPTIONS. Any other method answers 405 with code METHOD_NOT_ALLOWED and an Allow header, so a mistyped method fails loudly rather than looking like a write that did nothing.

Status codes

StatusMeaning
200Success
400Invalid request: malformed query parameter
401Unauthorized: invalid or missing API key
403Reserved. FORBIDDEN is for write endpoints, which have not shipped, so no v1 endpoint returns 403 today
404Not found: no such resource in the key's scope, or no endpoint at that path
405Method not allowed: the path exists but serves GET, HEAD and OPTIONS only
429Rate limited: too many requests
500Internal server error

Error codes

CodeStatusWhen
MISSING_AUTH401No Authorization header
INVALID_AUTH401Header is not Bearer {key}
INVALID_KEY401Malformed, unknown, or revoked API key
FORBIDDEN403Reserved for write endpoints, which have not shipped. No v1 endpoint returns this today
INVALID_PARAM400Query parameter failed validation
NOT_FOUND404Detail id does not exist in the key's scope, or no endpoint exists at that path
METHOD_NOT_ALLOWED405The path exists, but the method is not GET, HEAD or OPTIONS
RATE_LIMIT_EXCEEDED429Rate limit exceeded
INTERNAL_ERROR500Server error

Rate limits

  • 100 requests/min per API key
  • X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset headers are included on every 200 and every 429
  • No other error carries them. A 401 is decided before the key is identified, so there is no budget to report, and a 404 for an unknown path under /v1 is answered without reading the key at all. Read your remaining budget from a success or from the 429 itself, never from a 400, 401, 404 or 500
  • Rate-limited responses include a Retry-After header (seconds until reset) and the standard error envelope with code RATE_LIMIT_EXCEEDED

Versioning

The major version is the first path segment, and it is the whole compatibility promise.

Inside /v1, changes are additive. New endpoints, new fields on an existing response and new optional query parameters ship without notice, so read responses in a way that ignores fields you do not recognise rather than one that fails on them.

A change that could break a working client ships under a new prefix. Removing or renaming a field, changing its type, withdrawing an endpoint and tightening validation are all breaking. /v1 is not altered underneath you.

Deprecation and sunset

A withdrawal is announced before it happens, on the wire and not only in a changelog.

Once an endpoint is deprecated, every 200 it answers carries two headers:

  • Deprecation: an RFC 9745 structured-field date (@ followed by Unix seconds) naming when the deprecation took effect.
  • Sunset: an RFC 8594 HTTP-date naming when the endpoint stops answering.
Deprecation: @1688169599
Sunset: Sun, 30 Jun 2024 23:59:59 GMT

The sunset date is always at least 90 days after the deprecation date.

Neither header is on any endpoint today, because nothing is deprecated. Watch for their presence on a success rather than for their absence: errors do not carry them, since a 404 for an unknown path names no endpoint and a 400 or 401 is decided before the endpoint is reached.