platforms/devplace/rest_reporting_and_moderation.md

DevPlace REST: Reporting and Moderation Queue

The polymorphic report endpoint, the machine-readable reason list, and the administrator moderation queue: its state machine, actions, seniority rule and acknowledgement contract with the published review window.

Every externally visible surface on DevPlace is reportable through one polymorphic endpoint, and every report lands in one queue with one state machine. The reason list is served by GET /reports/reasons, so a native client renders the same dialog the web UI does.

DevPlace commits to reviewing every report within the window published on the content moderation page. Filing a report always returns an acknowledgement carrying that window.

The moderation endpoints under /admin/moderation are administrator-only and are subject to the admin seniority rule: a junior administrator cannot action a more senior one.

Every endpoint follows the shared Conventions & Errors (auth, content negotiation, pagination, status codes); see Authentication for the four ways to sign requests.

GET /reports/reasons - List report reasons

The reason keys a report may be filed under, with their labels.

Minimal role: Public

Sample response

{
  "reasons": [
    {
      "key": "harassment",
      "label": "Harassment or bullying"
    }
  ],
  "severities": [
    "info",
    "warn",
    "critical"
  ]
}

POST /reports/{targettype}/{targetuid} - Report content

File a report against any user-generated surface.

Minimal role: Member

Parameters

NameInTypeRequiredDescription
target_typepathenumyesThe kind of content being reported. Allowed: post, comment, gist, project, projectfile, news, attachment, message, quiz, poll, award, user, issue, workspace, deviioutput.
target_uidpathstringyesUID of the reported item.
reasonformenumyesWhy the content breaks the guidelines. Allowed: hate, violence, weapons, sexual, religious, misinformation, exploitative, harassment, spam, intellectualproperty, selfharm, illegal, other.
detailformstringnoFree text for the moderator, up to 2000 characters.

A second report on the same target by the same reporter updates the open report instead of creating a duplicate.

You cannot report your own content.

Sample response

{
  "ok": true,
  "redirect": "/reports/mine",
  "data": {
    "uid": "REPORT_UID",
    "status": "open",
    "severity": "warn",
    "sla_hours": 24
  }
}

GET /reports/mine - List your reports

The reports you filed and the outcome of each.

Minimal role: Member

Parameters

NameInTypeRequiredDescription
statusqueryenumnoFilter by report status. Allowed: open, acknowledged, actioned, dismissed.
pagequeryintegernoPage number.

Sample response

{
  "reports": [
    {
      "uid": "REPORT_UID",
      "target_type": "post",
      "target_uid": "POST_UID",
      "target_url": "/posts/a-post",
      "reason": "harassment",
      "reason_label": "Harassment or bullying",
      "detail": "Repeated personal attacks in the thread.",
      "severity": "warn",
      "status": "open",
      "origin": "member",
      "categories": [],
      "created_at": "2026-01-05T10:00:00+00:00",
      "resolved_at": "",
      "reporter_name": "alice",
      "owner_name": "bob",
      "report_count": 2
    }
  ],
  "pagination": {
    "page": 1,
    "total": 1,
    "total_pages": 1
  },
  "status": ""
}

GET /admin/moderation - The moderation queue

Reported content awaiting a decision, oldest open first.

Minimal role: Admin

Parameters

NameInTypeRequiredDescription
statusqueryenumnoFilter by report status. Allowed: open, acknowledged, actioned, dismissed.
pagequeryintegernoPage number.

Sample response

{
  "reports": [
    {
      "uid": "REPORT_UID",
      "target_type": "post",
      "target_uid": "POST_UID",
      "target_url": "/posts/a-post",
      "reason": "harassment",
      "reason_label": "Harassment or bullying",
      "detail": "Repeated personal attacks in the thread.",
      "severity": "warn",
      "status": "open",
      "origin": "member",
      "categories": [],
      "created_at": "2026-01-05T10:00:00+00:00",
      "resolved_at": "",
      "reporter_name": "alice",
      "owner_name": "bob",
      "report_count": 2
    }
  ],
  "counts": {
    "open": 1,
    "acknowledged": 0,
    "actioned": 0,
    "dismissed": 0
  },
  "sla": {
    "sla_hours": 24,
    "oldest_open_hours": 1.5,
    "breached": 0,
    "within_sla": true
  }
}

GET /admin/moderation/{uid} - Read one report

One report with its decisions and the author's history.

Minimal role: Admin

Parameters

NameInTypeRequiredDescription
uidpathstringyesReport UID.

Sample response

{
  "report": {
    "uid": "REPORT_UID",
    "target_type": "post",
    "target_uid": "POST_UID",
    "target_url": "/posts/a-post",
    "reason": "harassment",
    "reason_label": "Harassment or bullying",
    "detail": "Repeated personal attacks in the thread.",
    "severity": "warn",
    "status": "open",
    "origin": "member",
    "categories": [],
    "created_at": "2026-01-05T10:00:00+00:00",
    "resolved_at": "",
    "reporter_name": "alice",
    "owner_name": "bob",
    "report_count": 2
  },
  "actions": [],
  "history": [],
  "available_actions": [
    "remove_content",
    "restore_content",
    "warn",
    "suspend",
    "ban",
    "lift",
    "dismiss",
    "escalate"
  ],
  "can_remove": true
}

POST /admin/moderation/{uid}/status - Set a report status

Move a report through the triage state machine.

Minimal role: Admin

Parameters

NameInTypeRequiredDescription
uidpathstringyesReport UID.
statusformenumyesNew status. Allowed: open, acknowledged, actioned, dismissed.

Sample response

{
  "ok": true,
  "redirect": "/admin/moderation/REPORT_UID"
}

POST /admin/moderation/{uid}/decide - Decide a report

Apply a moderation decision and notify the affected user.

Minimal role: Admin

Parameters

NameInTypeRequiredDescription
uidpathstringyesReport UID.
actionformenumyesThe decision to apply. Allowed: removecontent, restorecontent, warn, suspend, ban, lift, dismiss, escalate.
reasonformstringnoReason shown to the affected user.
notesformstringnoInternal notes.
duration_hoursformintegernoSuspension length in hours.

A report already resolved by another moderator answers 409.

Content removal is unavailable for targets that have no removal path (direct messages, accounts, workspaces, polls, assistant output); act on the account instead.

Sample response

{
  "ok": true,
  "redirect": "/admin/moderation/REPORT_UID"
}

POST /admin/users/{uid}/suspend - Suspend an account

Suspend an account for a fixed period with a stated reason.

Minimal role: Admin

Parameters

NameInTypeRequiredDescription
uidpathstringyesUser UID.
reasonformstringnoReason shown to the user.
duration_hoursformintegernoSuspension length in hours.

A suspended account can still read, still see why, and still delete itself, but cannot create content.

Sample response

{
  "ok": true,
  "redirect": "/admin/users"
}

POST /admin/users/{uid}/lift - Lift a restriction

Clear a suspension or ban and restore the account.

Minimal role: Admin

Parameters

NameInTypeRequiredDescription
uidpathstringyesUser UID.

Sample response

{
  "ok": true,
  "redirect": "/admin/users"
}

POST /admin/users/{uid}/ban - Ban an account

Permanently close an account and revoke every credential.

Minimal role: Admin

Parameters

NameInTypeRequiredDescription
uidpathstringyesUser UID.
reasonformstringnoReason shown to the user.

Sample response

{
  "ok": true,
  "redirect": "/admin/users"
}

GET /auth/accept-terms - The terms acceptance page

The Terms of Service version in force and the version this account accepted.

Minimal role: Member

Sample response

{
  "terms_version": "1",
  "accepted_version": ""
}

POST /auth/accept-terms - Accept the terms

Record acceptance of the Terms of Service version in force.

Minimal role: Member

A member whose accepted version is behind the version in force is redirected here on any mutating request. Reading, the docs, the safety controls and account deletion are never blocked.

Sample response

{
  "ok": true,
  "redirect": "/feed",
  "data": {
    "terms_version": "1"
  }
}

POST /profile/{username}/consent - Grant or withdraw a consent

Change one consent on your own account. Withdrawal takes effect at once.

Minimal role: Member

Parameters

NameInTypeRequiredDescription
usernamepathstringyesYour own username.
kindformenumyesConsent to change. Allowed: terms, privacy, aithirdparty, activityrecording, containercredentials.
grantedformenumyes1 grants, 0 withdraws. Allowed: 1, 0.

Withdrawing aithirdparty makes the AI gateway refuse every call that would send your own content to the provider, whatever the per-feature preference says.

Withdrawing activity_recording stops presence writes; you simply appear offline.

Only the account holder can change a consent. An administrator reads the record but never grants or withdraws it for someone else.

Sample response

{
  "ok": true,
  "redirect": "/profile/USERNAME?tab=privacy",
  "data": {
    "kind": "ai_third_party",
    "state": "granted"
  }
}

POST /profile/{username}/mature-content - Set the mature-content preference

Show or hide content labelled mature for your own account.

Minimal role: Member

Parameters

NameInTypeRequiredDescription
usernamepathstringyesYour own username.
matureoptinformenumyes1 shows mature content, 0 hides it. Allowed: 1, 0.

Only the account holder can change this preference. An administrator reads the privacy tab but never sets it for someone else.

Sample response

{
  "ok": true,
  "redirect": "/profile/USERNAME?tab=privacy",
  "data": {
    "mature_opt_in": true
  }
}

GET /profile/{username}/delete - Account deletion page

What deletion removes, what is retained, and the grace window.

Minimal role: Member

Parameters

NameInTypeRequiredDescription
usernamepathstringyesYour own username.

Sample response

{
  "username": "USERNAME",
  "grace_hours": 24,
  "removed": [
    "Your account record, username, email address and password"
  ],
  "retained": [
    "Append-only audit and moderation records"
  ]
}

POST /profile/{username}/delete - Delete your account

Permanently delete your account and personal data.

Minimal role: Member

Parameters

NameInTypeRequiredDescription
usernamepathstringyesYour own username.
passwordformstringyesYour account password.

Only the account holder can delete an account; an administrator uses a ban instead.

Sessions and tokens are revoked and the profile is anonymised immediately; the deletion event is purged after the grace window.

Sample response

{
  "ok": true,
  "redirect": "/",
  "data": {
    "stamp": "2026-01-05T10:00:00+00:00",
    "rows": 42,
    "grace_hours": 24
  }
}

GET /workspaces/index - Published workspace index

Every workspace published to the public ingress, with its link.

Minimal role: Public

Parameters

NameInTypeRequiredDescription
pagequeryintegernoPage number.

The project-derived description and project_url come back empty unless you may view the workspace's project, so a private project never leaks its title or description through this public listing.

Sample response

{
  "workspaces": [
    {
      "uid": "INSTANCE_UID",
      "name": "demo",
      "slug": "demo",
      "owner_uid": "USER_UID",
      "url": "https://devplace.net/p/demo",
      "description": "A demo workspace.",
      "owner": "alice",
      "maturity": "general",
      "project_url": "/projects/demo"
    }
  ],
  "total": 1
}