Skip to content
Read API

Conventions

Every endpoint shares one key, one error shape and one rate limit.

Every request carries an organization read key as Authorization: Bearer sqly_ro_…. A read key is organization-wide (every project), created by an organization admin in Settings → API keys, and expires after 30, 60, 90, 180 days as chosen at creation. There is no renewal: create a new key and revoke the old one. Project ingest keys (sqly_…) are refused with wrong_key_type.

Every error is {"error": "<sentence>", "code": "<slug>"}. The sentence may be reworded; the slug may not. An id that does not exist and an id that belongs to another organization get the same 404, byte for byte.

HTTPCodeWhenWhat to do
400ambiguous_testSeveral tests have this name. Pass ?filePath= with one of: tests/a.spec.ts, tests/b.spec.ts.Repeat the request with ?filePath= set to one of the files the sentence lists.
400invalid_parametersha must be 4 to 40 hexadecimal characters (a commit SHA or a prefix of one).Fix the request; do not retry.
400invalid_perioddays=90 is beyond this plan’s 60-day retention. Use 60 or less.Use days=7, 30 or 90, within the plan’s retention; do not retry.
401invalid_keyInvalid read key.Check the key for typos or create a new one in Settings → API keys; do not retry.
401key_expiredThis read key expired on 2026-09-01. Create a new one in Settings > API keys.Create a new read key in Settings → API keys; keys are not renewed.
401key_revokedThis read key has been revoked.Create a new read key in Settings → API keys; this one will not work again.
401missing_keyMissing read key.Send the read key as Authorization: Bearer sqly_ro_…; do not retry without it.
401wrong_key_typeThis is a project ingest key. Read routes need an organization read key - Settings > API keys.Use an organization read key (sqly_ro_…), not a project ingest key; do not retry.
403tier_too_lowThe read API requires the Standard plan. This organization is on Free.Upgrade the organization to Standard or Pro; the same key works again after the upgrade.
404error_not_foundNo error signature with this fingerprint in this project.Take the fingerprint from GET /projects/{projectId}/errors; do not retry.
404project_not_foundNo project with this id in this organization.Take the project id from GET /projects; do not retry.
404run_not_foundNo run with this id in this project.Take the run id from GET /projects/{projectId}/runs; do not retry.
404test_not_foundNo test with this name in this project.Check the test name and filePath exactly as Squally shows them; do not retry.
429—More than 60 requests within 60 seconds with one read key.Wait 60 seconds, then retry. The edge counts requests per key in 60-second windows and sends no Retry-After header.
500internal_errorSomething went wrong on our side.Retry with exponential backoff, starting at 1 second and capped at 30 seconds.
Retry only on 429 and 5xx

429: wait 60 seconds, then retry. The edge counts requests per key in 60-second windows and sends no Retry-After header. 5xx: retry with exponential backoff, starting at 1 second and capped at 30 seconds. 400, 401, 403, 404: never retry - the same request gets the same answer.

Currently 60 requests per 60 seconds per key, counted per Authorization header - a read key has its own budget, shared with nothing else. Over the limit the edge answers 429 without a JSON body.

Lists that are computed whole page by number; the runs list pages with a cursor.

  • page: 1-based page number. A page past the end answers the last page.
  • perPage: Rows per page.
  • cursor: Opaque. Pass nextCursor for older runs, or prevCursor together with direction=prev for newer runs.
  • direction: Which way the cursor pages.

days: The period, in days, ending now. Must not exceed the plan’s retention (Standard 60, Pro 90 days); a longer period is refused with 400 invalid_period rather than answered with less data.