Skip to content

API documentation

SC Checker API 0.1.0

The machine-readable document is served by the API host at /v1/openapi.json. Keys are created on the API settings page.

Request crawls of a verified SuiteCommerce domain and read their results.

Availability

Enterprise and Partner plans. The public API is served on its own host, which answers the operations that carry an `x-scope`, this document at `/v1/openapi.json` and `/v1/health`, and nothing else. The other operations in this document are the web app’s, served on the private network under a signed-in session; a key reaching one is a 404. Every operation is contract-tested against the schemas the server validates with. PayPal’s webhook reaches the service through the web app and is not part of this document.

Authentication

`Authorization: Bearer scc_live_…`: `scc_live_` and 22 letters and digits. A key is shown once, when it is created or rotated, and is stored only as a keyed hash, so it cannot be shown again. Every refusal of a key is the same 401. A rotated key keeps working for 24 hours beside its successor. `scc_test_` keys are reserved: none is issued, and one presented is refused.

Scopes

Each operation a key may call names the one scope it needs in `x-scope`. A key without it is refused 403 `insufficient_scope`, naming the scope. The scopes are `domains:read`, `crawls:write`, `crawls:read`, `reports:read` and `webhooks:write`.

Rate limits

Per key and per organisation, counted across every server. Every response carries `X-RateLimit-Limit`, `X-RateLimit-Remaining` and `X-RateLimit-Reset`; a 429 carries `Retry-After` in seconds.

Idempotency

Every mutating call accepts `Idempotency-Key`. The key is matched together with a hash of the body: the same key with a different body returns 409 rather than the earlier result. The four operations whose answer is a credential — creating or rotating a key, creating a webhook endpoint, rotating its secret — are marked `x-idempotency-replay: false`: their answer is never stored, and any repeat of the key is a 409.

Webhooks

Every delivery is a POST of `WebhookPayload` carrying `X-SCChecker-Signature: t=<unix>,v1=<hex>`, the HMAC-SHA256 of `t + "." + body` under the endpoint’s signing secret. Reject a `t` more than five minutes from your own clock. For 24 hours after a secret is rotated the header carries a second `v1`; accept the delivery when any verifies. Delivery is at least once and `id` is the same on every retry: use it to discard a repeat.

Pagination

Cursor only. An offset over a table taking inserts skips and duplicates rows.

Errors

One envelope at every status: `{ error: { code, message, requestId } }`. Branch on `code`; `message` is for a person and may be reworded in any release.

Operations

  • GET /v1/crawls

    List crawls

    Scope crawls:read

  • POST /v1/crawls

    Request a crawl

    Scope crawls:write

    Spends credits at enqueue, not at completion. The depth decides the cost and the three budgets; everything else is derived server-side from the org’s entitlement, which is re-read inside the admission transaction.

  • GET /v1/crawls/{id}

    Read a crawl

    Scope crawls:read

  • GET /v1/crawls/{id}/events

    Stream a crawl’s progress

    Scope crawls:read

    Server-Sent Events over `crawl_events`. Each frame is `id: <ulid>`, `event: <type>`, `data: <CrawlEvent>`; a `: hb` comment every fifteen seconds keeps proxies from idling the connection. Send `Last-Event-ID` on reconnect to resume after that row. The stream closes after the `terminal` frame or after ten minutes, whichever comes first. Ownership is re-checked on every connection.

  • GET /v1/domains

    List verified domains

    Scope domains:read

    Read-only. Adding a domain needs proof of control — e-mail at the registrable domain, a DNS TXT record, or a tag in the SMT head — none of which an API key can supply, so it stays a wizard in the web app.

  • GET /v1/crawls/{id}/report.pdf

    Download a report as a PDF

    Scope reports:read

    The full report, rendered once and stored. 202 with `Retry-After` while it renders — the render is enqueued idempotently, so repeated calls are one job. `not_entitled` for a plan without PDF export or an audit outside the plan’s history window; `feature_unavailable` when this deployment has no renderer. The document’s date is the report’s own `generatedAt`, so a regenerated PDF of the same report is the same document.

  • GET /v1/domains/{id}

    Read a domain

    Scope domains:read

    One domain this organisation holds a claim on. A domain another organisation owns is a 404, indistinguishable from one that does not exist.

  • GET /v1/crawls/{id}/report

    Read a crawl’s report

    Scope reports:read

    The latest version of the report, projected through the plan: `visibility: full` for a plan with the full report and an audit inside its history window, the stored `summary` otherwise — a 200 either way, never a refusal, so a client can tell that the answer exists. `watermark` names the partner on a partner audit. Benchmark percentiles appear only on plans that include them. `format=markdown` answers the same projection as `text/markdown`. 404 until the crawl has a report.

  • GET /v1/webhooks

    List webhook endpoints

    Scope webhooks:write

    Every endpoint, oldest first. `display` is the host and the last four characters: a receiver URL is a credential and is never returned. `limit` is the most endpoints an organisation may hold.

  • POST /v1/webhooks

    Register a webhook endpoint

    Scope webhooks:write

    An https URL on a public hostname, and the events to send it. The URL is encrypted at rest and every delivery goes through the same guard as the crawler: public addresses only, and a redirect is refused. `secret` is in this response and nowhere else; every delivery is signed with it (see the document’s `webhooks`). `feature_unavailable` when this deployment has no encryption key; `destination_limit` past the most endpoints an organisation may hold.

  • GET /v1/webhooks/{id}

    Read a webhook endpoint

    Scope webhooks:write

    The endpoint and its ten most recent deliveries: each one’s status, the receiver’s HTTP status and a closed code. A receiver’s response body is never read or stored.

  • PATCH /v1/webhooks/{id}

    Change a webhook endpoint

    Scope webhooks:write

    Its events, its description, or whether it is enabled. Enabling an endpoint that was disabled — the receiver answered 410, or failed too many times in a row — clears the reason and the count. The URL cannot be changed: register a new endpoint.

  • DELETE /v1/webhooks/{id}

    Remove a webhook endpoint

    Scope webhooks:write

    The encrypted URL and secret, and the delivery history, go with it.

  • POST /v1/webhooks/{id}/test

    Send a test delivery

    Scope webhooks:write

    One signed `ping` now, and what the receiver answered: its status, never its body. Recorded with the deliveries; a failed ping never counts toward disabling the endpoint. Limited per endpoint per hour.

  • POST /v1/webhooks/{id}/rotate-secret

    Rotate a webhook signing secret

    Scope webhooks:write

    Returns the new secret once. For 24 hours deliveries carry a second `v1` under the previous secret, so a receiver can switch without missing one.