POST /v1/public/pages/{slug}/report
Submits an abuse report for a public page. This endpoint is unauthenticated.
The response is always 202 Accepted regardless of whether the slug exists — this is intentional. The endpoint never reveals page existence. Reports are forwarded to PostHog (and optionally Slack) for operator review. No database write occurs; takedown is handled by operator action through the standard unpublish mechanism.
Authentication
None. This is a public endpoint.
Path parameters
| Parameter | Type | Description |
|---|
slug | string | Page slug (pg_...) from the public URL. |
Request body
{
"reason": "spam",
"detail": "This page is impersonating a financial institution."
}
| Field | Type | Required | Description |
|---|
reason | string | No | Report category. One of: "spam", "phishing", "malware", "abuse", "copyright", "other". Unrecognized values are stored as "other". |
detail | string | No | Free-text description. Truncated to 2,000 characters server-side. |
Response
HTTP status: 202 Accepted.
| Field | Type | Description |
|---|
received | boolean | Always true. Indicates the report was accepted for review, not that the page was taken down. |
Error codes
| Code | Status | When |
|---|
rate_limited | 429 | Too many reports from this IP for this slug. |
All other responses are 202. A 202 for a missing slug is indistinguishable from a 202 for a valid one — this is intentional to prevent slug enumeration.
Notes
- No oracle:
202 is returned for any slug, including ones that do not exist.
- Async takedown: Submitting a report does not immediately take down the page. Operator review is required. Confirmed violations are handled via
DELETE /v1/artifacts/{id}/publish.
- Reason coercion: If
reason is missing, not a string, or not one of the recognized values, it is stored as "other".
Example
curl -X POST https://api.artifacta.io/v1/public/pages/pg_aB3xK9mP1qR5sT2u/report \
-H "Content-Type: application/json" \
-d '{"reason": "phishing", "detail": "Impersonating a bank login page."}'