sidequest_common.schemas.epgp#
EPGP loot system schemas.
Rules constants, the addon export/import wire shapes, and the HTTP API’s request/response schemas
(local://addon-contract.md is the source of truth; field names and string prefixes here are binding).
Attributes#
Weekly decay applied to EP and GP at every reset, read-time only ( |
|
The guild's single WoW: Forever realm, used when a member claims a character without specifying one. |
|
Exact shape of the |
|
EP awarded per |
|
GP by |
|
Off-spec pays this percent of main-spec GP, rounded half up. Alt fill and disenchant/bank pay 0. |
|
|
Classes#
|
|
Why an EP/GP ledger entry was written. |
|
How a |
|
Body for |
|
A |
|
Response for |
|
Body for |
|
Response for |
|
Body for |
|
Response for |
|
Response for |
|
One row of |
|
Response for |
|
One row of |
|
Response for |
|
One boss's kill/wipe tally on the progression board. |
|
One instance's bosses on the progression board. |
|
Response for |
|
One row of |
|
Body for |
|
The |
|
Response for |
|
One row of |
|
Body for |
|
Response for |
|
Response for |
|
One non-revoked sync token, without the secret ( |
|
One EP/GP ledger entry in the export payload. |
|
One boss pull entry in the export payload. |
|
One loot award entry in the export payload. |
|
The full decoded |
|
One raid session entry in the export payload. |
|
One session member entry in the export payload. |
|
One upcoming scheduled event in the game-import payload. |
|
The full |
|
One event sign-up in the game-import payload. |
|
One standings row in the game-import payload. |
|
What the attendance hand-off did for one import call. |
|
New vs. updated (re-imported, unchanged |
|
Whether a ledger entry is an EP or GP change. |
|
Where a ledger entry came from: the addon export, or a site-made officer adjustment. |
|
|
|
How a character rolled on an item. |
|
Body for |
|
EPGP roster status, settable by an officer ( |
Module Contents#
- class sidequest_common.schemas.epgp.AwardImportCounts#
Bases:
ImportCountsImportCountsplus rows newly voided by this import.- voided: int = 0#
- class sidequest_common.schemas.epgp.AwardReason#
Bases:
enum.StrEnumWhy an EP/GP ledger entry was written.
Initialize self. See help(type(self)) for accurate signature.
- ADJUST = 'adjust'#
- BOSS_KILL = 'boss_kill'#
- FULL_NIGHT = 'full_night'#
- LOOT = 'loot'#
- ON_TIME = 'on_time'#
- PROGRESS = 'progress'#
- STANDBY = 'standby'#
- class sidequest_common.schemas.epgp.CharacterSource#
Bases:
enum.StrEnumHow a
WowCharactergot linked to a member.Initialize self. See help(type(self)) for accurate signature.
- CLAIM = 'claim'#
- IMPORT = 'import'#
- OFFICER = 'officer'#
- SIGNUP = 'signup'#
- class sidequest_common.schemas.epgp.EpgpAdjustmentCreate#
Bases:
pydantic.BaseModelBody for
POST /api/epgp/adjustments(officer).- amount: int#
- kind: LedgerKind#
- member_id: int#
- reason: str#
- class sidequest_common.schemas.epgp.EpgpCharacter#
Bases:
pydantic.BaseModelA
WowCharacter, as returned by the characters admin screen and/api/me/characters.- id: uuid.UUID#
- is_main: bool#
- last_seen_at: datetime.datetime | None#
- member_id: int | None#
- member_name: str | None#
- model_config#
- name: str#
- realm: str#
- source: CharacterSource#
- wow_class: sidequest_common.schemas.events.WowClass | None#
- class sidequest_common.schemas.epgp.EpgpCharacterList#
Bases:
pydantic.BaseModelResponse for
GET /api/epgp/characters(officer) andGET /api/me/characters(member).- characters: list[EpgpCharacter]#
- class sidequest_common.schemas.epgp.EpgpCharacterUpdate#
Bases:
pydantic.BaseModelBody for
PUT /api/epgp/characters/{id}(officer).- is_main: bool#
- member_id: int | None#
- class sidequest_common.schemas.epgp.EpgpGameImport#
Bases:
pydantic.BaseModelResponse for
GET /api/epgp/game-import(officer).- generated_at: datetime.datetime#
- payload: str#
- class sidequest_common.schemas.epgp.EpgpImportBody#
Bases:
pydantic.BaseModelBody for
POST /api/epgp/imports: any text containing oneSQX1:string.- payload: str#
- class sidequest_common.schemas.epgp.EpgpImportResult#
Bases:
pydantic.BaseModelResponse for
POST /api/epgp/imports.- announcements: sidequest_common.schemas.guild_hub.AnnouncementImportCounts#
- attendance: ImportAttendanceResult#
- awards: AwardImportCounts#
- conflicts: list[str]#
Session external ids skipped by the one-recorder-per-raid-night conflict rule.
- encounters: ImportCounts#
- loot: LootImportCounts#
- recorder: str#
- sessions: ImportCounts#
- unlinked_characters: list[str]#
- class sidequest_common.schemas.epgp.EpgpLedgerPage#
Bases:
pydantic.BaseModelResponse for
GET /api/epgp/ledger(public), newest first.- entries: list[EpgpLedgerRow]#
- class sidequest_common.schemas.epgp.EpgpLedgerRow#
Bases:
pydantic.BaseModelOne row of
GET /api/epgp/ledger.- amount: int#
- at: datetime.datetime#
- character: str | None#
- decayed: float#
- id: uuid.UUID#
- item_name: str | None#
- kind: LedgerKind#
- member_id: int | None#
- member_name: str | None#
- note: str | None#
- officer: str#
- reason: str#
- voided: bool#
- class sidequest_common.schemas.epgp.EpgpLootPage#
Bases:
pydantic.BaseModelResponse for
GET /api/epgp/loot(public), newest first.- items: list[EpgpLootRow]#
- class sidequest_common.schemas.epgp.EpgpLootRow#
Bases:
pydantic.BaseModelOne row of
GET /api/epgp/loot.- at: datetime.datetime#
- character: str | None#
- encounter_name: str | None#
- gp: int#
- id: uuid.UUID#
- instance_name: str | None#
- item_id: int#
- item_name: str#
- member_id: int | None#
- member_name: str | None#
- quality: int#
- response: LootResponse#
- voided: bool#
- class sidequest_common.schemas.epgp.EpgpProgression#
Bases:
pydantic.BaseModelResponse for
GET /api/epgp/progression(public).- instances: list[EpgpProgressionInstance]#
- class sidequest_common.schemas.epgp.EpgpProgressionEncounter#
Bases:
pydantic.BaseModelOne boss’s kill/wipe tally on the progression board.
- encounter_id: int#
- first_kill_at: datetime.datetime | None#
- kills: int#
- last_attempt_at: datetime.datetime#
- name: str#
- wipes: int#
- class sidequest_common.schemas.epgp.EpgpProgressionInstance#
Bases:
pydantic.BaseModelOne instance’s bosses on the progression board.
- encounters: list[EpgpProgressionEncounter]#
- instance_id: int#
- name: str#
- size: int#
- class sidequest_common.schemas.epgp.EpgpRoster#
Bases:
pydantic.BaseModelResponse for
GET /api/epgp/roster(officer).- members: list[EpgpRosterRow]#
- class sidequest_common.schemas.epgp.EpgpRosterRow#
Bases:
pydantic.BaseModelOne row of
GET /api/epgp/roster(officer).- member_id: int#
- name: str#
- raid_status: RaidStatus | None#
- trial_started_at: datetime.datetime | None#
- class sidequest_common.schemas.epgp.EpgpRosterUpdate#
Bases:
pydantic.BaseModelBody for
PUT /api/epgp/roster/{member_id}(officer). Setting"trial"stampstrial_started_atnow.- raid_status: RaidStatus | None#
- class sidequest_common.schemas.epgp.EpgpRules#
Bases:
pydantic.BaseModelThe
rulesobject as returned byGET /api/epgp/standings(same shape as the game-import payload).- base_gp: int#
- chase_multiplier: float#
- decay_percent: int#
- ep: dict[str, int]#
- gp: dict[str, int]#
- legendary_gp: int#
- min_gp: int#
- os_percent: int#
- trial_days: int#
- class sidequest_common.schemas.epgp.EpgpStandings#
Bases:
pydantic.BaseModelResponse for
GET /api/epgp/standings(public).- generated_at: datetime.datetime#
- rows: list[EpgpStandingsRow]#
- class sidequest_common.schemas.epgp.EpgpStandingsRow#
Bases:
pydantic.BaseModelOne row of
GET /api/epgp/standings.- characters: list[str]#
- ep: float#
- gp: float#
- main: str | None#
- member_id: int | None#
- model_config#
- name: str#
- pr: float#
- trial: bool#
- wow_class: sidequest_common.schemas.events.WowClass | None#
- class sidequest_common.schemas.epgp.EpgpSyncTokenCreate#
Bases:
pydantic.BaseModelBody for
POST /api/epgp/sync-tokens(officer).- name: str#
- class sidequest_common.schemas.epgp.EpgpSyncTokenCreated#
Bases:
pydantic.BaseModelResponse for
POST /api/epgp/sync-tokens: the token shown once, never stored in plaintext.- id: uuid.UUID#
- name: str#
- token: str#
- class sidequest_common.schemas.epgp.EpgpSyncTokenList#
Bases:
pydantic.BaseModelResponse for
GET /api/epgp/sync-tokens(officer).- tokens: list[EpgpSyncTokenSummary]#
- class sidequest_common.schemas.epgp.EpgpSyncTokenSummary#
Bases:
pydantic.BaseModelOne non-revoked sync token, without the secret (
GET /api/epgp/sync-tokens, officer, own tokens only).- created_at: datetime.datetime#
- id: uuid.UUID#
- last_used_at: datetime.datetime | None#
- name: str#
- class sidequest_common.schemas.epgp.ExportAward#
Bases:
pydantic.BaseModelOne EP/GP ledger entry in the export payload.
- amount: int#
- at: int#
- character: str#
- id: str#
- kind: LedgerKind#
- loot_id: str | None = None#
- note: str | None#
- officer: str#
- reason: AwardReason#
- session_id: str | None = None#
- voided: bool = False#
- class sidequest_common.schemas.epgp.ExportEncounter#
Bases:
pydantic.BaseModelOne boss pull entry in the export payload.
session_id/ended_atmay be absent (seeExportSession).- characters: list[str]#
- difficulty_id: int#
- encounter_id: int#
- ended_at: int | None = None#
- id: str#
- name: str#
- session_id: str | None = None#
- size: int#
- standby: list[str]#
- started_at: int#
- success: bool#
- class sidequest_common.schemas.epgp.ExportLoot#
Bases:
pydantic.BaseModelOne loot award entry in the export payload.
- at: int#
- character: str#
- encounter_row_id: str | None = None#
- gp: int#
- id: str#
- inv_type: str#
- item_id: int#
- item_name: str#
- officer: str#
- quality: int#
- response: LootResponse#
- session_id: str | None = None#
- voided: bool = False#
- class sidequest_common.schemas.epgp.ExportPayload#
Bases:
pydantic.BaseModelThe full decoded
SQX1:payload, bounded per the contract.v: 2adds the guild-hub sections below; every v2 section is optional so av: 1addon keeps working unchanged.- addon_version: str#
- announcements: list[sidequest_common.schemas.guild_hub.ExportAnnouncement]#
- awards: list[ExportAward]#
- encounters: list[ExportEncounter]#
- exported_at: int#
- guild: str#
- loot: list[ExportLoot]#
- member_notes: list[sidequest_common.schemas.guild_hub.ExportMemberNote]#
- professions: list[sidequest_common.schemas.guild_hub.ExportProfession]#
- realm: str#
- recorder: str#
- recruits: list[sidequest_common.schemas.guild_hub.ExportRecruit]#
- roster: sidequest_common.schemas.guild_hub.ExportRoster | None = None#
- sessions: list[ExportSession]#
- signups: list[sidequest_common.schemas.guild_hub.ExportSignupV2]#
- v: int#
- class sidequest_common.schemas.epgp.ExportSession#
Bases:
pydantic.BaseModelOne raid session entry in the export payload.
Lua json encoders drop nil keys rather than emitting null, so every nullable contract field here is a pydantic default, not a required key: the addon may omit
event_id/ended_atentirely (e.g. a session exported before the raid ended) rather than sending them as JSONnull.- difficulty_id: int#
- ended_at: int | None = None#
- event_id: uuid.UUID | None = None#
- id: str#
- instance_id: int#
- instance_name: str#
- members: list[ExportSessionMember]#
- size: int#
- started_at: int#
- class sidequest_common.schemas.epgp.ExportSessionMember#
Bases:
pydantic.BaseModelOne session member entry in the export payload.
classarrives as the addon’s uppercase token (e.g."MAGE", Blizzard’sUnitClassreturn), normalized to lowercase before validation.- character: str#
- first_seen: int#
- last_seen: int#
- model_config#
- standby: bool = False#
- wow_class: sidequest_common.schemas.events.WowClass | None#
- class sidequest_common.schemas.epgp.GameImportEvent#
Bases:
pydantic.BaseModelOne upcoming scheduled event in the game-import payload.
- id: uuid.UUID#
- signups: list[GameImportSignup]#
- size: int | None#
- starts_at: int#
- title: str#
- class sidequest_common.schemas.epgp.GameImportPayload#
Bases:
pydantic.BaseModelThe full
SQI1:payload built byGET /api/epgp/game-import.members/newsare the public part (the addon may broadcast them);sheets/crafters/recipe_namesare on-demand (an officer’s addon answers members’ requests, never broadcasts the whole thing);officerstays on officers’ addons only. All four v2 additions are always present since the endpoint already requires an officer.- crafters: list[sidequest_common.schemas.guild_hub.GameImportCrafter]#
- events: list[GameImportEvent]#
- generated_at: int#
- killed_encounters: list[int]#
- members: list[sidequest_common.schemas.guild_hub.GameImportMember]#
- recipe_names: dict[str, str]#
- rules: dict#
- sheets: dict[str, sidequest_common.schemas.guild_hub.GameImportSheet]#
- standings: list[GameImportStandingsRow]#
- v: int#
- class sidequest_common.schemas.epgp.GameImportSignup#
Bases:
pydantic.BaseModelOne event sign-up in the game-import payload.
characteris the free-text sign-up name, no realm.- bench: bool#
- character: str#
- group: int | None#
- model_config#
- wow_class: sidequest_common.schemas.events.WowClass#
- class sidequest_common.schemas.epgp.GameImportStandingsRow#
Bases:
pydantic.BaseModelOne standings row in the game-import payload.
- characters: list[str]#
- ep: float#
- gp: float#
- main: str | None#
- member_id: int | None#
- model_config#
- name: str#
- pr: float#
- trial: bool#
- wow_class: sidequest_common.schemas.events.WowClass | None#
- class sidequest_common.schemas.epgp.ImportAttendanceResult#
Bases:
pydantic.BaseModelWhat the attendance hand-off did for one import call.
- event_id: uuid.UUID | None#
- marked: int = 0#
- class sidequest_common.schemas.epgp.ImportCounts#
Bases:
pydantic.BaseModelNew vs. updated (re-imported, unchanged
external_id) row counts.- new: int = 0#
- updated: int = 0#
- class sidequest_common.schemas.epgp.LedgerKind#
Bases:
enum.StrEnumWhether a ledger entry is an EP or GP change.
Initialize self. See help(type(self)) for accurate signature.
- EP = 'ep'#
- GP = 'gp'#
- class sidequest_common.schemas.epgp.LedgerSource#
Bases:
enum.StrEnumWhere a ledger entry came from: the addon export, or a site-made officer adjustment.
Initialize self. See help(type(self)) for accurate signature.
- ADDON = 'addon'#
- SITE = 'site'#
- class sidequest_common.schemas.epgp.LootImportCounts#
Bases:
ImportCountsImportCountsplus rows newly voided by this import.- voided: int = 0#
- class sidequest_common.schemas.epgp.LootResponse#
Bases:
enum.StrEnumHow a character rolled on an item.
Initialize self. See help(type(self)) for accurate signature.
- ALT = 'alt'#
- BANK = 'bank'#
- COUNCIL = 'council'#
- DE = 'de'#
- MS = 'ms'#
- OS = 'os'#
- class sidequest_common.schemas.epgp.MyCharacterCreate#
Bases:
pydantic.BaseModelBody for
POST /api/me/characters(member). 409 if another member already claimed this name-realm.- model_config#
- name: str#
- realm: str | None = None#
- wow_class: sidequest_common.schemas.events.WowClass | None#
- class sidequest_common.schemas.epgp.RaidStatus#
Bases:
enum.StrEnumEPGP roster status, settable by an officer (
PUT /api/epgp/roster/{member_id}).Initialize self. See help(type(self)) for accurate signature.
- RAIDER = 'raider'#
- TRIAL = 'trial'#
- sidequest_common.schemas.epgp.AWARD_AMOUNT_MAX = 1000#
- sidequest_common.schemas.epgp.AWARD_AMOUNT_MIN = -1000#
- sidequest_common.schemas.epgp.BASE_GP = 100#
- sidequest_common.schemas.epgp.CHASE_MULTIPLIER = 1.5#
- sidequest_common.schemas.epgp.DECAY_PERCENT = 15#
Weekly decay applied to EP and GP at every reset, read-time only (
amount * (1 - DECAY_PERCENT/100) ** resets).
- sidequest_common.schemas.epgp.DEFAULT_REALM = 'Whitemane'#
The guild’s single WoW: Forever realm, used when a member claims a character without specifying one.
- sidequest_common.schemas.epgp.EPGP_RULES: dict[str, object]#
Exact shape of the
rulesobject in theSQI1:import string.
- sidequest_common.schemas.epgp.EP_VALUES: dict[str, int]#
EP awarded per
AwardReason.standbyearns the same as the raid (on_time/full_night/boss kills).
- sidequest_common.schemas.epgp.GP_BY_INVTYPE: dict[str, int]#
GP by
INVTYPE_*at main-spec cost. A 1H “main caster weapon” uses the 2H cost (200) by officer toggle; tier tokens use the cost of the slot the officer picks; chase items areslot cost * CHASE_MULTIPLIER; legendary pieces are flatLEGENDARY_GP. None of those three cases key offinv_typealone, so they aren’t in this map.
- sidequest_common.schemas.epgp.LEGENDARY_GP = 300#
- sidequest_common.schemas.epgp.MAX_AWARDS = 20000#
- sidequest_common.schemas.epgp.MAX_ENCOUNTERS = 500#
- sidequest_common.schemas.epgp.MAX_IMPORT_BYTES = 2097152#
- sidequest_common.schemas.epgp.MAX_LOOT = 1000#
- sidequest_common.schemas.epgp.MAX_NAME_LENGTH = 64#
- sidequest_common.schemas.epgp.MAX_NOTE_LENGTH = 200#
- sidequest_common.schemas.epgp.MAX_SESSIONS = 50#
- sidequest_common.schemas.epgp.MIN_GP = 100#
- sidequest_common.schemas.epgp.OS_PERCENT = 10#
Off-spec pays this percent of main-spec GP, rounded half up. Alt fill and disenchant/bank pay 0.
- sidequest_common.schemas.epgp.TRIAL_DAYS = 14#
- sidequest_common.schemas.epgp.WEEKLY_RESET_HOUR_UTC = 15#
- sidequest_common.schemas.epgp.WEEKLY_RESET_WEEKDAY = 1#
datetime.weekday()value for Tuesday.