- Sells as: the
content-moderation product (a product-scoped API key). This capability has no separate product-face contract — its public product route reuses the capability contract below; see the Edge route table's Product face row.
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
- Console: Manage the
content-moderation product in the console →
- Runbook: operational checklist for
content-moderation — internal (Vagary Labs ops; not part of this public site): docs/runbooks/capability-operations.md#content-moderation
- Public base:
https://api.vagarylabs.com (the consolidated API gateway — one host, per-brand sibling api.<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
Edge route table
The routes this capability actually serves on the public edge — live-synced from GET https://api.vagarylabs.com/product/v1/_meta/catalog (snapshot v1). The metric is the request-granularity billing counter; the scope is the key permission required.
Product face (customer-keyed)
| Method | Path | Metric | Scope |
|---|
POST | /product/v1/moderation/reports | moderation_reports | write |
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. The Edge route table section is synced from the live edge catalog snapshot (v1) — re-sync with python3 scripts/sync-edge-catalog.py.