monoesdocs
Menu

Errors & conventions

Status codes and shared behavior

Conventions that apply across most of the API reference rather than to any one endpoint.

Status codes

400

Bad request

Validation failure. Body shape is usually { "error": "some_code_or_message" } — error naming is not fully consistent (see below).

401

Unauthenticated

No session cookie and no valid Bearer token.

403

Forbidden

Authenticated, but missing the required scope or role, or the account is blocked.

404

Not found

The resource id doesn't exist, or you don't have visibility into it.

409

Conflict

A uniqueness constraint failed — but not every conflict uses 409, see below.

429

Rate limited

Only on the headless email-claim endpoints today.

The 400-vs-409 line isn't drawn consistently yet: POST /api/community/labels returns 409 on a duplicate name, but POST /api/community/username returns 400 for the same class of conflict. Check the specific endpoint's entry in the reference rather than assuming.

How a request is authenticated

Every scope-checked route accepts two different kinds of credential, and they behave differently:

  • A browser session cookie(the same one the monoes.me web app uses) is accepted first, and if present it short-circuits the check entirely — the endpoint's declared scope is not verified against it. A signed-in browser session can call any scope-checked route.
  • A Bearer token (OAuth-issued or from the headless agent flow) is checked against its stored scopes array with exact string matching — community:write does not imply community:read. If you need both, request both scopes.

Blocked accounts

A blocked user hitting a scope-only write route (most of the API) gets { "error": "Account blocked" }. On a role-gated (admin/moderator) route the check can't tell "wrong role" apart from "blocked" — both collapse into a generic { "error": "Forbidden" }. Either way, a blocked user also can't start a new browser session; existing sessions are invalidated.

Pagination

The one paginated endpoint, GET /api/community/feed, uses a 0-indexed page query parameter — the first page is page=0, not page=1.