Hoard uses the Django session for both HTTP and WebSocket authentication. HTTP is
limited to CSRF/session operations and raw .cah byte transfer:
GET /api/auth/csrf/GET,POST, andDELETE /api/auth/session/POST /api/uploads/character-imports/<upload_id>/
Campaign domain data is not exposed through HTTP REST routes.
/ws/user/lists the signed-in user's active acting contexts./ws/contexts/<context_id>/resolves that exact GM or PC context and joins its campaign broadcast group./ws/invites/<token>/inspects and claims a single invitation. It supports anonymous inspection and registration.
Requests contain a type, a fresh UUIDv7 request_id, and operation fields.
Queries receive query.result or query.error; commands receive command.ack
or command.error. Correlated replies echo request_id. Errors include a stable
code, human-readable detail, and field_errors where validation identified
specific fields. Campaign sockets reconnect and clients authoritatively rerun
their required queries after reconnecting.
Query-result data, command payloads, and domain-event data are defined with
Pydantic models. These models are transport-neutral: WebSocket consumers and
temporary HTTP compatibility handlers serialize them with model_dump(mode="json").
The context socket exposes campaign state/calendar, members, invitations, party XP,
encounters, and read-only DiceCloud character projections. Commands include
campaign.get, characters.dicecloud.link, characters.dicecloud.unlink,
characters.active.set, campaign.experience.recipients.set, and
experience.shared_awards.create.
The invite socket supports invite.inspect, invite.accept, and
invite.register_and_accept. The user socket supports user.contexts.list.
- Send
characters.imports.cah.beginwith the target character. - Upload one
.cahfile to the returned same-origin URL using multipart, session authentication, and CSRF. The endpoint returns only204. - Send
characters.imports.cah.previewwith the upload ID. - Review calculations, warnings, and inventory mappings.
- Send
characters.imports.cah.commitwith the preview token, orcharacters.imports.cah.cancel.
Upload IDs are single-use, limited to 5 MiB, target-bound, and expire after 15 minutes. Preview and commit domain data travels only over WebSocket.
Ledger and audit responses include occurred_at, campaign_date, and actor.
The real timestamp is UTC-backed and the campaign date is the snapshot captured
when the event posted. Unknown legacy snapshots are null and display as
Campaign date unavailable. Campaign dates are formatted like PD 81, 21st.