---
title: "Publish a report"
method: POST
path: "/v1/reports"
tags: ["Reports"]
---

# Publish a report

`POST /v1/reports`

## Request

- Base URL: `https://api.squirrelscan.com`
- URL: `https://api.squirrelscan.com/v1/reports`
- Auth: HTTP bearer

Publish an audit report. The report payload is the full `AuditReport` produced by the CLI/engine. Visibility defaults to `private`. **Publishing is included in the audit's base charge**; no visibility carries a separate credit charge. `unlisted` and `private` publishes always create a new report (no idempotency). Org-scoped `public` publishes are keyed on the publisher + a content hash: republishing the identical payload is an idempotent replay, returning the original report with `200` if the prior response was cached, or `409` otherwise (still in flight / not cached).

## Request body

- PublishReportRequest
  - `report` AuditReport, required: The full audit report payload produced by the squirrelscan engine. Only the high-signal top-level fields are documented here; the complete schema is validated by the hosted API. Extra top-level fields are accepted but ignored, while the documented fields below are validated and must conform.
    - `baseUrl` string, uri, required
    - `timestamp` string, date-time, required
    - `totalPages` integer, required
    - `passed` integer, required
    - `warnings` integer, required
    - `failed` integer, required
    - `siteChecks` object[], required
    - `pages` object[]
    - `summary` object, required
    - `ruleResults` object, required
    - `healthScore` object
  - `visibility` 'public' | 'unlisted' | 'private'

## Response `200`

Idempotent replay of an identical org-scoped `public` publish whose original response was cached — returns the originally published report.

- PublishedReport
  - `id` string, required
  - `url` string, uri, required
  - `visibility` 'public' | 'unlisted' | 'private', required
  - `createdAt` string, date-time, required

## Other responses

- `201`: Report published.
- `400`: The body failed validation (`VALIDATION_ERROR`, with `error.issues`), was not valid JSON (`INVALID_JSON`), or tripped the content security scanner (`SECURITY_VIOLATION`, with `error.threats`).
- `401`: Missing or invalid credentials (including the shared auth middleware: no/invalid bearer token). Typed envelope with code `UNAUTHORIZED`. Branch on the `401` status, not the message.
- `402`: The organization does not have enough credits for this operation. Typed envelope with code `INSUFFICIENT_CREDITS`; `error.required` and `error.balance` carry the credit detail. Branch on the `402` status.
- `409`: An identical request was already processed under the same idempotency key and is still in flight or its cached response is unavailable. Typed envelope with code `DUPLICATE_REQUEST`.
- `413`: The request body exceeds the maximum allowed size.
- `429`: Too many requests. Retry after the window resets. (Rate limiting is planned — issue #69 — these headers document the intended contract.)

---

[API](https://skmtc.dev/squirrelscan/apis/squirrelscan-public-api.md) · [All operations](https://skmtc.dev/squirrelscan/apis/squirrelscan-public-api/llms.txt) · [OpenAPI document](https://skmtc.dev/squirrelscan/apis/squirrelscan-public-api/revisions/82c8183fe8bc?raw)
