Skip to main content
The SnowSEO API lets you access your SEO data programmatically. Use it to run audits, check keyword rankings, fetch analytics, or embed SnowSEO data into your own dashboards, scripts, and integrations.
The API is available on the Scale plan. Generate API keys from Settings → Integrations → API in your dashboard. A brand key works for one brand; an organization key works for every brand in the organization. Only organization admins and owners can create or delete keys.

Base URL

All API requests go to this base URL:
Every endpoint path starts with /v3, for example https://api.snowseo.com/v3/seo-audit. Responses are JSON, except long-running endpoints such as a single-page POST /v3/seo-audit, which stream newline-delimited JSON (see Streaming responses). Send request bodies as JSON with the Content-Type: application/json header.

What You Can Do With the API


Authentication

All endpoints require an API key in the Authorization header:
The key can also be sent in an x-api-key header. Brand keys start with sk_team_ (older ones with sk_) and organization keys with sk_org_. Both are generated in Settings → Integrations → API. See the Authentication guide for full details on creating keys, scoping, and security best practices.

How to Make a Request

Here’s the typical pattern for any API call:
For GET requests, pass parameters as query strings:

Your First Integration

Here’s a minimal Node.js example to get you started:
A brand key carries your brand automatically, so there is no teamId to pass. With an organization key, pass the brand’s teamId on each request.

Endpoints Overview

The API is organized into these categories: Browse all endpoints using the navigation on the left.

Date Windows

Endpoints that take a date window accept either startDate and endDate (YYYY-MM-DD) or days.
  • days counts back from today on the team’s calendar, in the team’s time zone (UTC if the team has none).
  • The API turns days into startDate and endDate before reading any data, so every number in one response covers the same window.
  • days is ignored when startDate or endDate is sent.
  • With no window, endpoints use the last 30 days. Keyword history defaults to 90 days, the keyword timeline to 365, and the AI visibility prompt list to your full history.
  • endDate without startDate means All Time where the endpoint supports it.
  • startDate without endDate runs to today on the team’s calendar.
  • Search Console data lags 2-3 days, so a window ending today is clamped to Google’s newest day.

Response Format

Successful responses return the data directly:
Every error response has the same shape: success: false, a human-readable error, and a machine-readable code. Some add fields that explain more (for example requiredCredits, retryAfterSeconds, featureId), and a 500 adds a reference to quote to support.
Branch on code, not on the error text. Without a more specific code, code falls back to the HTTP status: BAD_REQUEST, UNAUTHORIZED, PAYMENT_REQUIRED, FORBIDDEN, NOT_FOUND, CONFLICT, UNPROCESSABLE, TOO_MANY_REQUESTS, INTERNAL_ERROR, UPSTREAM_ERROR, SERVICE_UNAVAILABLE. Common specific codes: A few endpoints, such as IndexNow, also return message.

Streaming responses

Long-running endpoints (a single-page POST /v3/seo-audit, for example) reply with Content-Type: application/x-ndjson. The stream sends blank keep-alive whitespace and {"status": "..."} lines, then the result as the last JSON line. Once streaming starts the HTTP status is already 200, so a failure arrives in-band as a final {"success": false, "error": "...", "code": "..."} line. Read the response line by line and check the last line for error. Validation, plan, and conflict errors are returned before streaming starts, with a real status code.

Rate Limits

Limits apply at three levels:
  • Per API key: 120 requests per 60 seconds.
  • Per route: varies by endpoint, for example 100 requests per minute for /v3/seo-audit and 150 for rank-tracking endpoints.
  • Global: 240 requests per minute for the organization.
When any of these limits is hit, the API returns 429 with a retryAfterSeconds hint:
Handling rate limits:
  • Wait for the number of seconds indicated by retryAfterSeconds
  • If you don’t have a retryAfterSeconds value, use exponential backoff (1s, 2s, 4s, 8s…)
  • If you’re regularly hitting the limit, batch your requests or add delays between calls

Error Handling

The API uses standard HTTP status codes: Always check both the HTTP status code and the error field in the response body:

Testing with cURL

The quickest way to test the API is with cURL from your terminal:

SDKs & Client Libraries

Currently, the API is raw HTTP - no official SDK yet. The authentication guide has examples in Node.js and Python that you can copy into your project. If you build a client library, let us know and we can list it here.

Need Help?