---
title: "Submit a scan"
method: POST
path: "/api/v1/scans"
tags: ["scans"]
---

# Submit a scan

`POST /api/v1/scans`

## Request

- Base URL: `https://api.sytecheck.app` (the document declares no server; this is the origin it was published from)
- URL: `https://api.sytecheck.app/api/v1/scans`
- Auth: HTTP bearer

Queue a website scan and return immediately with its id and a `queued` status.

A scan opens a real browser, runs a Lighthouse audit, and has screenshots
reviewed by a vision model, so it takes a few minutes rather than seconds. Poll
`GET /api/v1/scans/{scan_id}`, subscribe to `GET /api/v1/scans/{scan_id}/stream`,
or supply a `webhook_url` to be notified on completion.

**Each scan draws on your monthly quota.** Omit `categories` to run everything
your plan includes; request specific ones with `GET /api/v1/scans/categories`.

Refusals are distinguishable and worth handling separately:

- `403` — your plan does not include a requested category, webhooks, or the
  scan credit you asked to spend. Retrying will not help.
- `422` — the URL or a category id is not valid.
- `429` — monthly quota, concurrent scan limit, or daily burst cap. A
  `Retry-After` header says when to try again.

A scan that ends `failed` — its URL unreachable, or every category errored or
blocked — is voided: it is marked with `quota_refunded_at`, costs no quota, and
returns any spent credit.

## Query parameters

- `lang` string, nullable: Language for report content (e.g. 'es', 'pt-BR'). Falls back to the Accept-Language header, then English.

## Headers

- `accept-language` string, nullable

## Request body

- ScanCreate: Body for POST /api/v1/scans.
  - `url` string, uri, required
  - `label` string, nullable
  - `categories` string[], nullable: Analysis categories to run. Omit to run every category included in your plan. Valid values: "html", "seo", "links", "visual", "ai_visibility", "accessibility", "performance", "security_headers", "responsive", "content_freshness".
  - `webhook_url` string, uri, nullable: Optional URL to receive a POST with the completed scan payload once analysis finishes. Delivery is retried on failure.
  - `use_scan_credit` boolean: Spend one purchased scan credit on this scan instead of your monthly quota. Runs every analysis category regardless of your plan. Credits are never spent unless you set this.

## Response `201`

Successful Response

- ScanResponse: Scan summary — returned by POST and in the scan history list.
  - `id` integer, required
  - `url` string, required
  - `label` string, nullable, required
  - `status` 'queued' | 'scanning' | 'summarizing' | 'complete' | 'failed', required
  - `categories_requested` string[], required
  - `overall_score` number, nullable, required
  - `error_message` string, nullable
  - `webhook_url` string, nullable
  - `quota_refunded_at` string, date-time, nullable
  - `used_scan_credit` boolean
  - `created_at` string, date-time, required
  - `completed_at` string, date-time, nullable, required

## Other responses

- `422`: Validation Error

---

[API](https://skmtc.dev/sytecheck/apis/sytecheck-api.md) · [All operations](https://skmtc.dev/sytecheck/apis/sytecheck-api/llms.txt) · [OpenAPI document](https://skmtc.dev/sytecheck/apis/sytecheck-api/revisions/797cf6b3e867?raw)
