Content moderation
This capability is granted by an API key scoped to the `` product (product face). See the product reference below.
Content-report-queue capability — a durable, org-scoped report-lifecycle FSM: a user reports content (dup-suppressed: one open PENDING report per (org, article, user)) → it enters an admin review queue → an admin transitions it dismissed | reviewed | actioned. Plus GDPR endpoints: Art. 20 export (a user's reports) and Art. 17(3)(e) anonymize-retain (rebind the reporter user_id in place + stamp anonymized_at, retaining the record — content-moderation evidence is regulatory-retained). Per-vertical thresholds / category rules / the news ForumCategoryManager + DMCA takedown FSM stay product-local (I5). I4: own Postgres store, never a product Mongo.
- Group: Content & media
- Contract:
contracts/content-moderation/v1/openapi.yaml - Public base:
https://api.vagarylabs.com(the consolidated API gateway — one host, per-brand siblingapi.<zone>) - Auth: a product API key (
vgk_…) issued from the console —Authorization: Bearer vgk_… - Product face (customer-keyed):
https://api.vagarylabs.com/product/v1/moderation/reports
Endpoints
| Method | Path | Summary |
|---|---|---|
POST | /v1/reports | File a report (dup-suppressed) for the caller's org |
GET | /v1/reports | List reports (filter by status / article_id / site_id), newest-first |
GET | /v1/reports/pending | The review queue (status='pending') |
GET | /v1/reports/count | Queue depth (optionally by status) |
GET | /v1/reports/export | GDPR Art. 20 — every report a user filed (org-scoped) |
POST | /v1/reports/anonymize | GDPR Art. 17(3)(e) — anonymize (rebind user_id + stamp anonymized_at) and RETAIN a user's reports |
POST | /v1/reports/{report_id}/review | FSM transition — dismiss |
GET | /health | liveness |
GET | /metrics | Prometheus |
Schemas
SubmitRequest
| Field | Type | Description |
|---|---|---|
organization_id | string | product-tier tenant (I6) |
article_id | string | the reported content id |
user_id | string | the reporter |
reason | string | |
details | string | free text, truncated to the details cap |
site_id | string | multi-brand sub-site (within the org); omit for a global report |
ReviewRequest
| Field | Type | Description |
|---|---|---|
organization_id | string | |
action | string | the FSM verb |
reviewer_id | string | |
notes | string |
AnonymizeRequest
| Field | Type | Description |
|---|---|---|
organization_id | string | |
user_id | string | the reporter user_id to anonymize |
anon_user_id | string | the anonymized rebind value, e.g. [deleted_<prefix>] |
Report
| Field | Type | Description |
|---|---|---|
id | string | |
article_id | string | |
user_id | string | |
reason | string | |
details | string | |
status | string | |
created_at | number | epoch seconds |
reviewed_at | ['number', 'null'] | |
reviewer_id | ['string', 'null'] | |
notes | string | |
site_ids | array | present only when the report was site-scoped |
duplicate | boolean | true when an open PENDING report already existed (dup-suppressed) |
ReportList
| Field | Type | Description |
|---|---|---|
reports | array | |
count | integer |
CountResult
| Field | Type | Description |
|---|---|---|
count | integer |
ExportResult
| Field | Type | Description |
|---|---|---|
reports | array | |
user_id | string |
AnonymizeResult
| Field | Type | Description |
|---|---|---|
anonymized | integer | number of reports rebound + retained |
user_id | string | |
anon_user_id | string |
Generated by scripts/gen-capability-docs.py from contracts/content-moderation/v1/openapi.yaml — the contract IS the source of truth; edit the contract, not this page.