- Authenticate with a
platform:adapter-scoped API key minted on platform.opennotes.ai. - Identify end users with
X-Adapter-*headers on every request. - Drive the same set of endpoints under
/api/public/v1. - React to community consensus via webhooks (or polling as a fallback).
How to read this guide
Onboarding
Start on platform.opennotes.ai —
register your community, add your instance, mint an API key, and pick a
moderation tier. This unlocks everything else.
Concepts
Learn the three things every request carries: an API key (scope), identity
headers (user context), and the endpoints those keys can reach.
The public API contract
An integration is any service that connects a community platform (Discourse, Discord, Reddit, …) to the Open Notes API. The public API contract defines the exact responsibilities on each side. Follow it and your integration gets scoring, community review, and decision delivery automatically.What an integration does
Submit content
Call
POST /api/public/v1/requests with the content and platform context headers whenever a user posts or a moderator flags something.Carry user identity
Send
X-Adapter-* headers so Open Notes knows who submitted the content. The server uses this to weight rater influence and detect patterns.Apply decisions
Listen for
moderation.decision webhooks and apply the action on the source platform (hide, delete, flag, notify).Record actions
After applying a decision, call
POST /api/public/v1/moderation-actions so the audit trail is complete.What the server guarantees
| Guarantee | Detail |
|---|---|
| Idempotent submission | Submitting the same request_id twice returns the existing record, not a duplicate. |
| At-least-once delivery | Webhooks are retried up to 3 times with exponential backoff (10 s, 30 s, 90 s). |
| Authenticated identity | X-Platform-* spoofing from external callers is stripped by middleware. Only valid platform:adapter keys can attach user context via X-Adapter-*. |
| Stable IDs | Request IDs, note IDs, and rating IDs are UUID v7 and never reused. |
| Public API isolation | The /api/public/v1 surface is versioned and will not break without a major version bump and a deprecation notice. |
Minimum viable integration
A minimal integration needs exactly three things:- A
platform:adapter-scoped API key (see Mint API keys). - Logic to call
POST /api/public/v1/requestswhen content should be reviewed. - A webhook endpoint that receives
moderation.decisionevents and applies the action.
Header shape (summary)
Every request your integration makes must include:Security boundary
The server enforces two layers of security:- API key authentication — the
Authorization: Bearerheader is checked first. A missing or invalid key returns HTTP 401. - Scope check — the key must include
platform:adapter. Any key without this scope returns HTTP 403 on integration endpoints.
X-Platform-* headers (used by internal services) are stripped from all external requests by InternalHeaderValidationMiddleware before they reach any route handler. External integrations cannot spoof platform-level identity — they can only assert user-level identity via X-Adapter-*, which is gated behind the platform:adapter scope check.
The Discourse plugin as reference implementation
The Discourse plugin is the canonical reference. It implements the full public API contract end-to-end in production. If this guide is ambiguous, treat the Discourse plugin as the source of truth — its source code is the tie-breaker.| Contract piece | Discourse plugin implementation |
|---|---|
| Submit content | OpenNotes::Client#post("/api/public/v1/requests", ...) called from a PostCustomField job |
| Carry user identity | execute_request sets all six X-Adapter-* headers from the Discourse User object |
| Apply decisions | Discourse Silence / Hide Post / Delete API called from the webhook handler |
| Record actions | POST /api/public/v1/moderation-actions called after every platform action |
| Auth | X-API-Key header with the key stored in the opennotes_api_key site setting |
plugin/lib/opennotes/client.rb. Reading it is the fastest way to understand the full flow.