Moderation
Layer 1 moderation: what a server operator controls on their own infrastructure. Every operation here requires an admin session - see Server Administration.
An operator’s reach is deliberately narrow. They can decide who gets tokens from their server and which peers they federate with. They cannot see conduct, because they cannot decrypt anything, and no protocol path reports it to them.
| Layer | Answers for | Specified in |
|---|---|---|
| Server | the blobs it stores, and who it issues tokens to | this page |
| Group | conduct within a group | Moderation Architecture |
| Device | what one person sees | Client-side Blocking |
struct DeviceRecord { device_id: DeviceId,
// The only timestamp a server holds for a device. Everything after // announcement is anonymous announced_at: u64,
trust_tier: TrustTier, admin_verified: bool,
// Current issuance budget, including any override bucket: TokenBucket, custom_budget_expires_at: Option<u64>,}VerifyDevice
Section titled “VerifyDevice”Grants a device the Verified Trust Tier immediately, skipping the 24-hour climb.
- Input:
VerifyRequest { device_id, reason } - Output:
DeviceRecord - Auth: Admin session
- Idempotent: Yes
- Errors:
ADMIN_UNAUTHORIZED,ADMIN_INSUFFICIENT_PERMISSIONS,DEVICE_NOT_ANNOUNCED
Requirements
Section titled “Requirements”- Servers MUST reject a
device_idwith no announcement record - Verification MUST raise only the issuance budget, and MUST NOT make the device’s activity observable
- Servers MUST record the acting administrator in the audit log
- Verification MUST persist across announcement renewal
Verification is keyed by device_id because issuance is where a server authenticates a device. A verified device’s tokens are indistinguishable from anyone else’s when spent.
HTTP Binding
Section titled “HTTP Binding”POST /admin/v1/trust/verifyAuthorization: AdminSession <token>BlockDevice
Section titled “BlockDevice”Sets a device’s budget to zero.
- Input:
BlockRequest { device_id, reason } - Output:
DeviceRecord - Auth: Admin session
- Idempotent: Yes
- Errors:
ADMIN_UNAUTHORIZED,ADMIN_INSUFFICIENT_PERMISSIONS,DEVICE_NOT_ANNOUNCED
Requirements
Section titled “Requirements”- Blocking MUST set
rateandcapacityto zero - Servers MUST NOT retract tokens already issued; those remain spendable until they expire
- Servers MUST record the acting administrator and the stated reason
- Blocking MUST persist across announcement renewal
- Servers MUST return
DEVICE_BLOCKEDat issuance thereafter
HTTP Binding
Section titled “HTTP Binding”POST /admin/v1/trust/blockAuthorization: AdminSession <token>SetCustomBudget
Section titled “SetCustomBudget”Overrides a device’s bucket parameters for a bounded period.
- Input:
BudgetRequest { device_id, rate, capacity, expires_at } - Output:
DeviceRecord - Auth: Admin session
- Idempotent: Yes
- Errors:
ADMIN_UNAUTHORIZED,ADMIN_INSUFFICIENT_PERMISSIONS,DEVICE_NOT_ANNOUNCED,CONFIG_INVALID
Requirements
Section titled “Requirements”rateandcapacityMUST be non-negative- Servers MUST reject an
expires_atin the past - Servers MUST revert to the tier default at
expires_at - An override MUST NOT change how tokens are verified at redemption
HTTP Binding
Section titled “HTTP Binding”POST /admin/v1/trust/budgetAuthorization: AdminSession <token>GetDeviceRecord
Section titled “GetDeviceRecord”Returns everything a server holds about one device.
- Input: None -
device_idin the path - Output:
DeviceRecord - Auth: Admin session
- Idempotent: Yes
- Errors:
ADMIN_UNAUTHORIZED,DEVICE_NOT_ANNOUNCED
Requirements
Section titled “Requirements”- Servers MUST NOT return message counts, delivery counts, or any per-device traffic figure
- Servers MUST NOT return mailbox addresses; no mapping from device to mailbox exists
- Servers MUST return
DEVICE_NOT_ANNOUNCEDfor an expired record rather than a partial one
HTTP Binding
Section titled “HTTP Binding”GET /admin/v1/trust/devices/{device_id}Authorization: AdminSession <token>ListPendingVerification
Section titled “ListPendingVerification”Devices an operator may want to verify - announced recently, still below Trusted.
- Input:
PendingQuery { min_age_hours, limit } - Output:
Vec<DeviceRecord> - Auth: Admin session
- Idempotent: Yes
- Errors:
ADMIN_UNAUTHORIZED
Requirements
Section titled “Requirements”- Servers MUST order results by
announced_at - Servers MUST exclude blocked devices
- Servers MUST bound
limit, defaulting to 100
HTTP Binding
Section titled “HTTP Binding”GET /admin/v1/trust/pending?min_age_hours={n}&limit={n}Authorization: AdminSession <token>BulkVerifyDevices
Section titled “BulkVerifyDevices”- Input:
BulkVerifyRequest { device_ids, reason } - Output:
BulkResult { verified, failed } - Auth: Admin session
- Idempotent: Yes
- Errors:
ADMIN_UNAUTHORIZED,ADMIN_INSUFFICIENT_PERMISSIONS
Requirements
Section titled “Requirements”- Servers MUST report per-device outcomes rather than failing the batch on one error
- Servers MUST apply the same rules as
VerifyDeviceto each entry - Servers MUST bound the batch size and return
CONFIG_INVALIDbeyond it
HTTP Binding
Section titled “HTTP Binding”POST /admin/v1/trust/verify-bulkAuthorization: AdminSession <token>BlockOrigin
Section titled “BlockOrigin”Refuses federation with a peer.
- Input:
BlockOriginRequest { server_domain, reason } - Output:
BlockRecord { server_domain, reason, blocked_at, blocked_by } - Auth: Admin session
- Idempotent: Yes
- Errors:
ADMIN_UNAUTHORIZED,ADMIN_INSUFFICIENT_PERMISSIONS
Requirements
Section titled “Requirements”- Servers MUST refuse blocked origins before verifying
X-Origin-Signature, so a blocked peer costs no cryptographic work - Servers MUST return
ORIGIN_BLOCKEDto a blocked peer - Servers MUST NOT deliver queued envelopes that arrived from the peer before the block
- Servers MUST record the acting administrator
HTTP Binding
Section titled “HTTP Binding”POST /admin/v1/federation/block/{server_domain}Authorization: AdminSession <token>UnblockOrigin
Section titled “UnblockOrigin”- Input: None - domain in the path
- Output: None
- Auth: Admin session
- Idempotent: Yes
- Errors:
ADMIN_UNAUTHORIZED,ADMIN_INSUFFICIENT_PERMISSIONS
Requirements
Section titled “Requirements”- Servers MUST succeed for a domain that is not currently blocked
- Servers MUST re-fetch the peer’s discovery document before accepting traffic again, since its signing key may have rotated
HTTP Binding
Section titled “HTTP Binding”DELETE /admin/v1/federation/block/{server_domain}Authorization: AdminSession <token>ListBlockedOrigins
Section titled “ListBlockedOrigins”- Input: None
- Output:
Vec<BlockRecord> - Auth: Admin session
- Idempotent: Yes
- Errors:
ADMIN_UNAUTHORIZED
Requirements
Section titled “Requirements”- Servers MUST include both manual and automatic blocks, distinguishing the two
HTTP Binding
Section titled “HTTP Binding”GET /admin/v1/federation/blocklistAuthorization: AdminSession <token>GetOriginReputation
Section titled “GetOriginReputation”- Input: None - domain in the path
- Output:
OriginReputation - Auth: Admin session
- Idempotent: Yes
- Errors:
ADMIN_UNAUTHORIZED
struct OriginReputation { server_domain: String,
// 0.0 to 1.0, higher is better reputation_score: f32,
// All observed by this server. None of it requires reading an envelope metrics: OriginMetrics,
federation_status: FederationStatus, // Active | Limited | Blocked
// Timestamp of the first time this server was interacted with first_contact: u64,
// Timestamp of the last known activity from this server last_activity: u64,}
struct OriginMetrics { envelopes_delivered: u64,
// Rejected for malformation, version mismatch, or an unadvertised feature envelopes_rejected: u64,
// Deliveries to addresses that were never registered. A peer guessing // addresses produces these; a legitimate one almost never does unknown_mailbox_attempts: u64,
uptime_percentage: f32, certificate_valid: bool,}Requirements
Section titled “Requirements”- Reputation MUST be derived only from observed delivery behavior
- Servers MUST NOT attribute any metric to a device
- Servers MUST recompute on access rather than storing a stale score
score = 1.0 - (unknown_mailbox_ratio x 0.5) - (rejection_ratio x 0.3) - (blocklist_penalty x 0.05)HTTP Binding
Section titled “HTTP Binding”GET /admin/v1/federation/reputation/{server_domain}Authorization: AdminSession <token>SetFederationPolicy
Section titled “SetFederationPolicy”- Input:
FederationPolicy - Output:
FederationPolicy - Auth: Admin session
- Idempotent: Yes
- Errors:
ADMIN_UNAUTHORIZED,ADMIN_INSUFFICIENT_PERMISSIONS,CONFIG_INVALID
struct FederationPolicy { // When true, federate only with servers in the allowlist allowlist_mode: bool, allowlist: Vec<String>,
// Auto-block peers scoring below this. None disables it auto_block_threshold: Option<f32>,
require_certificate_validation: bool,
// Publish the blocklist at /.well-known/cryptid-blocklist publish_blocklist: bool,}Requirements
Section titled “Requirements”auto_block_thresholdMUST be between 0.0 and 1.0 when present- Servers MUST return the policy as stored, so a client can confirm what applied
- Enabling
allowlist_modewith an empty allowlist MUST be rejected asCONFIG_INVALID - Servers MUST record the acting administrator
HTTP Binding
Section titled “HTTP Binding”PUT /admin/v1/federation/policyAuthorization: AdminSession <token>GetPublishedBlocklist
Section titled “GetPublishedBlocklist”A server MAY publish which peers it blocks, letting operators share defederation decisions without a central authority.
- Input: None
- Output:
Vec<BlockRecord> - Auth: None
- Idempotent: Yes
- Errors:
UNKNOWN_OPERATION
Requirements
Section titled “Requirements”- Publication MUST be opt-in, via
publish_blocklist - Servers MUST return
UNKNOWN_OPERATIONwhen publication is disabled - The document MUST NOT name any device or user
- Operators MUST treat another server’s blocklist as advisory, never as automatic input
HTTP Binding
Section titled “HTTP Binding”GET /.well-known/cryptid-blocklistWhat an Operator Cannot Do
Section titled “What an Operator Cannot Do”- Read message content, which is always encrypted
- Learn who sent anything, since redemption is anonymous
- Count a device’s messages, for the same reason
- See group membership, which is client-side state
- Remove someone from a group, which is a moderator’s action inside MLS
- Block a device anywhere but their own server