Skip to content

Errors

The Sharpe API uses RFC 9457 Problem Details for error responses. Every error is a flat JSON object with a machine-readable type URI, a human-readable title, the HTTP status code, a detailed message, and the request ID for debugging.

Error format

Every error response is a flat RFC 9457 Problem Details object at the top level. There is no ok field or nested error wrapper.

Properties

  • Name
    type
    Type
    string
    Description

    A URI reference that identifies the error type (e.g., https://www.sharpe.ai/errors/invalid_parameter). Use this for programmatic error handling.

  • Name
    title
    Type
    string
    Description

    A short, human-readable summary of the error.

  • Name
    status
    Type
    integer
    Description

    The HTTP status code.

  • Name
    detail
    Type
    string
    Description

    A human-readable explanation of what went wrong and how to fix it.

  • Name
    request_id
    Type
    string
    Description

    Unique request identifier (e.g., req_abc123def456ghij). Include this when contacting support.

  • Name
    doc_url
    Type
    string
    Description

    Link to the relevant documentation page for troubleshooting this error.

  • Name
    suggested_action
    Type
    string
    Description

    Actionable guidance on how to resolve this error.

Error response

{
  "type": "https://www.sharpe.ai/errors/invalid_parameter",
  "title": "Invalid Parameter",
  "status": 400,
  "detail": "Invalid parameter \"type\": Invalid enum value. Expected 'current' | 'accumulated' | 'history'",
  "request_id": "req_abc123def456ghij",
  "doc_url": "https://www.sharpe.ai/docs/errors#error-codes",
  "suggested_action": "Check the parameter value against the endpoint documentation. Use GET /v1/futures/coins or GET /v1/meta/coverage to discover valid values."
}

Error codes

Here is the complete list of error types returned by the Sharpe API. Use the type URI for programmatic branching and the status code for broad categorization.

  • Name
    invalid_api_key
    Type
    401
    Description

    The provided API key is malformed or has been revoked. Double-check your Authorization: Bearer or X-API-Key header.

  • Name
    expired_api_key
    Type
    401
    Description

    The API key has expired. Generate a new key from the Sharpe dashboard.

  • Name
    insufficient_scope
    Type
    403
    Description

    Your API key does not have the required scope to access this resource. Check the scopes assigned to your key.

  • Name
    monthly_quota_exceeded
    Type
    429
    Description

    You have exhausted your monthly request quota. Retryable: wait for the reset in the Retry-After header, or upgrade your plan.

  • Name
    invalid_parameter
    Type
    400
    Description

    A query parameter has an invalid value. Check the detail field for specifics.

  • Name
    missing_parameter
    Type
    400
    Description

    A required query parameter is missing from the request.

  • Name
    rate_limit_exceeded
    Type
    429
    Description

    You have exceeded your per-minute rate limit. Wait until the time indicated by the X-RateLimit-Reset header.

  • Name
    resource_not_found
    Type
    404
    Description

    The requested endpoint or resource does not exist. Verify the URL path.

  • Name
    internal_error
    Type
    500
    Description

    An unexpected error occurred on our side. These are automatically reported to our team.

  • Name
    upstream_error
    Type
    502
    Description

    A dependency failed to respond. Used only by endpoints that do not yet carry the freshness envelope (their reference pages list 502). Retry with exponential backoff.

  • Name
    service_unavailable
    Type
    503
    Description

    A data source or our data store is temporarily unavailable, and nothing stored could be served instead. The detail names the source (for example GoPlus Security is unavailable.), and Retry-After says when to try again: 60 seconds for an upstream source, 30 for the data store. Every endpoint that carries the freshness envelope answers an outage this way; 502 is not used there.

An answer the server could only partly build is not an error: it is a 200 whose meta.runtime_status is degraded (with X-Data-Partial naming the reads that were cut short, or X-Data-Fallback when the server's last good answer or a stored snapshot stands in). Degraded answers are never cached, so a retry after a short wait can return the complete one. See Data freshness.


Retry guidance

Not all errors are retryable. Here is how to handle each category:

4xx client errors: do not retry

These indicate a problem with your request. Fix the issue before retrying.

  • 400: Fix the invalid or missing parameter
  • 401: Check your API key is valid and not expired
  • 403: Create a key with the scopes this endpoint requires
  • 404: Verify the URL

429 rate limit and quota: retry after the reset

Both limit rejections are retryable and both return 429. Use Retry-After when present, or X-RateLimit-Reset for the per-minute window:

  • rate_limit_exceeded: the per-minute window is exhausted. It reopens at X-RateLimit-Reset.
  • monthly_quota_exceeded: the monthly quota is exhausted. It reopens at X-Quota-Reset, and Retry-After carries the seconds until then.

429 response headers

HTTP/2 429
x-ratelimit-limit: 30
x-ratelimit-remaining: 0
x-ratelimit-reset: 1743062472
retry-after: 12
x-request-id: req_abc123def456

Wait for Retry-After seconds, or until the Unix timestamp in X-RateLimit-Reset, before sending the next request.

5xx server errors: exponential backoff

For 500, 502, and 503 errors, retry with exponential backoff (and never sooner than Retry-After when it is present):

  1. Wait 1 second, then retry
  2. Wait 2 seconds, then retry
  3. Wait 4 seconds, then retry
  4. Continue doubling up to a maximum of 30 seconds
  5. After 5 retries, stop and alert your monitoring system

Troubleshooting

"My key works in cURL but fails in my app"

The most common cause is the Authorization header being stripped or malformed. Check that:

  • The header is exactly Authorization: Bearer sk_live_... with a single space after Bearer
  • Your HTTP client is not URL-encoding the header value
  • No proxy or CDN between your app and www.sharpe.ai is stripping the Authorization header. If one is, use X-API-Key instead

"I get 403 but my plan should include this endpoint"

A 403 is always insufficient_scope: the key was created with restricted scopes. Generate a new key with the required scope, or contact support to update scopes on the existing key. Quota exhaustion is not a 403. It returns a retryable 429.

"I keep hitting 429 even at low volume"

A 429 can mean two things. Check the type field in the error response:

  • rate_limit_exceeded: Rate limits are per-minute fixed windows. If you send 30 requests in 2 seconds (within a single 60-second window), you will exhaust a Free tier limit instantly. Spread requests evenly across the minute or implement the backoff pattern from the rate limits guide.
  • monthly_quota_exceeded: You have hit your plan's monthly request limit, so every request fails until the quota resets. Check your usage at GET /v1/usage, then either wait out the Retry-After window or upgrade your plan.

"I get 502 or 503 intermittently"

These mean an upstream dependency (a data source or our data store) is temporarily unavailable and nothing stored could be served instead. Wait for Retry-After, then retry with exponential backoff. If the error persists for more than 5 minutes, contact support with the X-Request-Id.

"Response data is empty or stale"

Some endpoints depend on cron jobs that populate data on a schedule (for example, current funding rates every 5 minutes and the heatmap cache every 3 hours and narrative caches every 4 hours). If you query immediately after a new endpoint is deployed, data may not yet be populated. Read the freshness envelope below: it states the data's age and whether it is past its SLA.


Data freshness

Every endpoint served by the freshness envelope (all of v1 except /v1/funding/rates, /v1/funding/coins, /v1/futures/data, /v1/futures/coins, /v1/market/derivatives-overview, /v1/arbitrage/spot-perp, /v1/arbitrage/cross-exchange, /v1/rug-check/trending, /v1/analytics/query and the system routes) says how fresh its answer is, in meta and in headers. A successful answer that is stale or incomplete is still a 200: read these fields instead of the status code.

  • Name
    meta.as_of
    Type
    string | null
    Description

    When the data was current: the dataset's own time (the newest live row, the snapshot or refresh time, or the fetch time), never the response time. null when unknown.

  • Name
    meta.stale_after
    Type
    string | null
    Description

    as_of plus the freshness SLA. Past this instant the data is stale, however long a copy was cached: re-judge a stored copy against it.

  • Name
    meta.freshness_sla_seconds
    Type
    integer
    Description

    The dataset's SLA: its writer's cadence plus one skipped run. GET /v1/meta/coverage lists each product's datasets with their cadence and SLA.

  • Name
    meta.freshness_status
    Type
    string
    Description

    fresh within the SLA, stale past it, unknown when as_of is null, judged when the answer was built (meta.generated_at).

  • Name
    meta.runtime_status
    Type
    string
    Description

    degraded when this read was incomplete: a leg timed out or failed, a row budget was hit (meta.truncated), or a fallback answered (meta.served_from: "last-good" or a stored snapshot). ok otherwise.

  • Name
    meta.dataset_id, served_from, source, coverage, warnings, truncated, generated_at
    Type
    various
    Description

    The dataset read, where the rows came from, the upstream sources behind them, how complete the stored data is (coverage.used of coverage.expected, drops by reason), what the read could not do, and when the answer was built.

The same facts travel as headers on every free and v1 answer of these endpoints: X-Data-As-Of, X-Data-Stale-After, X-Data-Stale (true unless fresh), X-Data-Status (fresh, stale, degraded or fallback), X-Freshness-Sla-Seconds, X-Data-Source (comma-separated source ids) and X-Data-Coverage (used/expected). Free endpoints whose body is a JSON object carry the fields in their own meta key too; a bare-array body has the headers only.

Was this page helpful?