Skip to main content

Authentication

Every request needs your API key in the X-API-Key header. The Python SDK reads it from the PROFOUND_API_KEY env var.
Generate a key in the app under Settings → API Keys. Treat it like a password — it has full read access to your org’s analytics data.

Rate limit

600 requests per hour, per key. Anything above returns 429 Too Many Requests. Cache responses where you can and batch period-over-period or multi-asset queries instead of fanning out.

end_date is exclusive — add one day

end_date is parsed at the start of that day in Eastern Time, so it’s excluded from the response. To include all of May 10, send end_date="2026-05-11". The date_interval buckets ("day" / "week" / "month") are also computed in ET.

Read column positions from info.query, not your request

Each row in the response packs its metrics and dimensions as arrays. The order of values in those arrays comes from info.query.metrics and info.query.dimensionsnot from the order you sent in the request. Always look it up:
A response always looks like this:

Period-over-period deltas are client-side

The API doesn’t return change vs the previous period. Run the same call twice — current window and a prior window of equal length — and subtract.

Don’t average daily rows to get a period score

A call with dimensions=["date"] returns one row per day. A call without date returns one row for the whole window. These are different numbers: the period score is traffic-weighted, an average of daily rows is not. Use the no-date call for headlines; use the with-date call for charts. Never derive one from the other.

Pagination

Default pagination.limit is 100. Max is 50,000. Use info.total_rows (returned on every response) to decide whether to paginate. Almost all queries fit in a single 50k page; only heavy dimensions=["url", ...] citation queries usually need a second page.
If you do need more, increment offset by limit until you’ve covered total_rows.

Filters

Every report endpoint accepts a filters array of {field, operator, value} objects:
prompt_type (with values like "visibility") maps to the app’s view toggles. Send prompt_type=visibility on Citations / Visibility queries to mirror the default UI scope.

Error responses

Timezones

All bucketing happens in Eastern Time. A “last 7 days” range anchored to your local clock can land on a different ET day than you expect. Anchor scheduled jobs to ET: