Errors & rate limits

When a request fails, the Ranksy API returns a consistent error envelope alongside an appropriate HTTP status code. The code is a stable, machine-readable string you can branch on; the message is human-readable and may change.

Error envelope

Every error response wraps a single error object. The type groups related codes (for example invalid_request_error or authentication_error); code is the specific, stable identifier; message explains what happened; param (when present) names the first offending field; and doc_url links to this reference, anchored at the failing code.

  • Name
    type
    Type
    string
    Description

    The error category, e.g. invalid_request_error, authentication_error, permission_error, integration_error.

  • Name
    code
    Type
    string
    Description

    The stable, machine-readable error code (see below).

  • Name
    message
    Type
    string
    Description

    A human-readable description. Do not parse this.

  • Name
    param
    Type
    string
    Description

    Present on validation errors: the name of the first failing query parameter.

  • Name
    doc_url
    Type
    string
    Description

    Link to the documentation for this code: https://api.ranksyapp.com/errors#{code}.

Error response

{
  "error": {
    "type": "invalid_request_error",
    "code": "validation_failed",
    "message": "end_date must be greater than or equal to start_date.",
    "param": "end_date",
    "doc_url": "https://api.ranksyapp.com/errors#validation_failed"
  }
}

Error codes

Each code below has an anchor matching its code string, so doc_url (https://api.ranksyapp.com/errors#{code}) links straight here.

422invalid_request_error

validation_failed

One or more query parameters are invalid — a malformed date, end_date earlier than start_date, an out-of-range per_page, an unknown granularity, and so on. The param field names the first failing field.

400invalid_request_error

unknown_metric

The {metric} in the path is not one of the 12 catalog metrics.

400invalid_request_error

unsupported_basis

The basis query parameter is not valid for a churn metric. churn_rate and revenue_churn_rate accept only real_churn in v1; any other value is rejected. param is basis.

400invalid_request_error

invalid_basis

The basis query parameter is not one the ltv metric supports. Pass month (the default) or year. param is basis and the message lists the supported values.

400invalid_request_error

unsupported_filter

A filter query parameter (plan, billing_interval, install_status, status) was supplied to a metric that cannot honor it. Ranksy never silently ignores a filter — the request is rejected and param names the offending filter.

401authentication_error

missing_api_key

No API key was supplied, or the key is unknown, revoked, or expired. Send a valid key as Authorization: Bearer rk_live_….

401authentication_error

missing_team_scope

The key is valid but is not bound to a team, so no apps can be resolved. Reissue the key with a team.

422invalid_request_error

team_missing

The authenticated account has no team, so the request cannot be clamped to one. Unlike missing_team_scope (which is about an API key without a team), this is the account itself missing a team — join or create a team before calling the API.

402payment_required_error

subscription_required

The REST API requires an active Ranksy subscription and this team has none — a lapsed subscription, or a trial that expired without converting. Ingestion writes still work; reads need an active plan. Subscribe to re-enable the key.

403permission_error

insufficient_scope

The key is valid but lacks the ability required for this endpoint. Reissue the key with the needed scope (or *).

403permission_error

insufficient_permissions

The key is valid and team-scoped but lacks the metrics:read (or *) scope required to read metrics.

404invalid_request_error

resource_not_found

A sub-resource named by a query parameter — a keyword string or a category — is not tracked for this app. The request is well-formed but there is no data for that value; param names the offending parameter.

404invalid_request_error

shop_not_identified

The /capi endpoint received a myshopify_domain with no installation for this app. /capi only enriches an existing installation — call /identify for the domain first. param is myshopify_domain.

409integration_error

partner_integration_not_connected

The app's Shopify Partner integration has not been connected, so no partner metrics can be served. Connect it in Ranksy settings. param is app.

409integration_error

partner_integration_unauthorized

The app's Shopify Partner integration was rejected or its authorization was revoked. Reconnect it in Ranksy. param is app.

409integration_error

partner_integration_pending

The app's Shopify Partner integration is still initializing. The first sync has not completed yet; retry once it finishes. param is app.

409integration_error

bigquery_integration_not_connected

The app's GA4 BigQuery export has never been connected, so traffic and install analytics cannot be served. Connect it in Ranksy settings. param is app.

409integration_error

bigquery_integration_unauthorized

BigQuery rejected Ranksy's credentials for this app (permission revoked or rotated). Reconnect the integration to resume syncing traffic and install data. param is app.

409integration_error

bigquery_integration_pending

The app's BigQuery integration is still initializing — the first sync has not imported data yet. Retry in a few hours. param is app.

422shopify_error

shopify_token_invalid

The Shopify access token provided to the /identify endpoint is invalid, expired, or has been revoked. Generate a new token and retry.

422invalid_request_error

app_events_token_expired

The app_events_token supplied to /track is a JWT whose exp claim is already in the past, so Shopify would reject the forward with a 401 Token has expired. Ranksy checks expiry up front: the call is rejected and nothing is recorded or forwarded. Mint a fresh token with the client_credentials grant (see Track events) — App Events tokens live 60 minutes. param is app_events_token.

429rate_limit_error

too_many_requests

You exceeded the per-minute request limit. Wait for the number of seconds in the Retry-After header, then retry. See Rate limits below for the window and headers.

429rate_limit_error

quota_exceeded

Your team has spent its monthly billable-request quota for the current billing cycle. Only reads count toward it — ingestion writes (/identify, /track, /capi) and usage read-backs (/usage-events, /usage-metrics) keep working past a spent quota. Upgrade your plan for a higher ceiling, or wait for the cycle to reset. See Plan quota and metering.

422invalid_request_error

tracked_keyword_quota_exceeded

Tracking these keywords would exceed the app's tracked-keyword allowance for your plan. This is a per-app product limit, distinct from quota_exceeded (the billable-request ceiling). The message reports the remaining headroom; untrack keywords or upgrade to make room, then retry with a smaller batch.

502shopify_error

shopify_api_error

The Shopify Admin API returned a server error or is unreachable when called by the /identify endpoint. Ranksy does not retry; the caller should retry with exponential backoff.


Rate limits

Requests are rate-limited per app on a single rolling window:

  • Name
    Per minute
    Type
    120 requests
    Description

    A rolling per-minute limit of 120 requests, applied independently to each app you track — one busy app never eats into another's budget.

Endpoints that aren't scoped to a single app (listing your apps, and the /identify, /track, /capi ingestion endpoints) fall back to a per-team window; unauthenticated requests (such as the health check) fall back to a per-IP window.

Every response carries standard X-RateLimit-* headers so you can track your remaining budget:

Rate-limit headers

X-RateLimit-Limit: 120
X-RateLimit-Remaining: 117
X-RateLimit-Reset: 1716998400

When you exceed the limit, the API responds with 429 Too Many Requests (too_many_requests) and a Retry-After header indicating how many seconds to wait before retrying:

429 response headers

HTTP/1.1 429 Too Many Requests
Retry-After: 12

Plan quota and metering

The rate limit above is a burst guard applied per app, and its 429 carries a Retry-After. Separately, each billing cycle your team has a monthly quota of billable requests set by your plan — the same ceiling whether you call the REST API or MCP. Spending it returns 429 quota_exceeded (documented above); the fix is a higher plan or the next cycle, not a short wait.

Only reads count. A billable request is a GET (or HEAD) to a data endpoint. Everything else is free and never decrements your quota:

  • Name
    Ingestion writes
    Type
    never metered
    Description

    POST /identify, POST /track, and POST /capi are your own backend pushing data into Ranksy — /track fires on every merchant page view. Metering them would bill you for feeding us data, so they keep working even after your read quota is spent. A quota stop never severs your event stream.

  • Name
    Usage read-backs
    Type
    never metered
    Description

    GET /usage-events and GET /usage-metrics return only your own /track data, so reading your own events back is free too.

When your team spends its cycle quota, further reads return 429 quota_exceeded while writes and usage read-backs continue. Upgrade your plan for a higher ceiling, or wait for the cycle to reset.

What counts against your quota

EndpointMethodCounts against quota
Apps, Metrics, Subscriptions, Transactions, LTV cohortsGETYes
Customers, NotesGETYes
Rankings, Traffic & installsGETYes
Reviews, Scorecard, Competitors, Category catalogGETYes
Identify, Track events, Conversion signalsPOSTNo
Usage events, Usage metricsGETNo
Health check (/__ping)GETNo

Was this page helpful?