{"endpoints":[{"method":"GET","path":"\/api\/stages","description":"Stage collection, surface data only. All, many or one, depending on the filters.","notes":["Stages the dump carries no display code for are never listed; ask for them by id or alias on \/api\/stages\/{key}.","The default ordering, and sort=code, is human order -- 0-2 before 0-10 -- not alphabetical.","`mapCount` is how many map images the wiki has for the stage: 1 for a plain \u003Ccode\u003E_map.png, 2 where the files are numbered \u003Ccode\u003E_map_1.png and _2.png instead, 0 when there is none. See `maps` below."],"filters":{"q":"free text over code, name and description","stageId":"exact stage id; comma-separated or repeated for several","code":"display code; comma-separated or repeated","zoneId":"zone; comma-separated or repeated","stageType":"MAIN, SUB, DAILY, ...; comma-separated or repeated","difficulty":"NORMAL, FOUR_STAR, ...; comma-separated or repeated","diffGroup":"comma-separated or repeated","appearanceStyle":"comma-separated or repeated","performanceStageFlag":"comma-separated or repeated","mainStageId":"exact","canon":"exact canon key of the source record","event":"all stages of an event, by event id (e.g. act41side); comma-separated or repeated","alias":"exact match against any lookup key of a stage","apCostMin":"integer","apCostMax":"integer","bossMark":"boolean","hilightMark":"boolean","isStoryOnly":"boolean","canPractice":"boolean","hasLevel":"boolean; whether level data was imported for the stage","itemId":"only stages whose drop table contains this item id","enemyKey":"only stages that field this enemy, e.g. enemy_1007_slime","sort":"code, name, stageId, zoneId, apCost, expGain, goldGain, dangerPoint, stageType, difficulty, id (code sorts in human order)","order":"asc or desc","page":"integer, 1-based","limit":"integer, capped by AKUP_MAX_PAGE_SIZE"}},{"method":"GET","path":"\/api\/stages\/{key}","description":"One stage with everything: level payload and video guides included.","notes":["{key} is a stage id, canon key, display code or alias.","URL-encode the key; some stage ids contain \u0022#\u0022.","Add ?raw=1 to also get the untouched source `excel` object.","`videos` lists the guides for this stage -- the videos of creators typed Guidemaker -- creators in priority order, newest upload first within a rank. Detail only.","`videosSpecial` lists every other video that names the stage: specialists\u0027 niche clears, entertainers\u0027 runs, whatever the creator\u0027s types say. Same ordering, same entry shape. Detail only."]},{"method":"GET","path":"\/api\/events","description":"Event collection: just enough to identify an event and place it in time -- id, name, date and displayType. Newest first, with the un-dated main story chapters (MAINLINE) sorting last. Only events with displayType SIDESTORY, MINISTORY, BOSS_RUSH or MAINLINE are listed.","filters":{"page":"integer, 1-based","limit":"integer, capped by AKUP_MAX_PAGE_SIZE"}},{"method":"GET","path":"\/api\/events\/{key}","description":"One event with every stage it covers, and each stage\u0027s videos.","notes":["{key} is the numeric id, or the event\u0027s own id (e.g. act41side).","`stages` lists every stage belonging to this event, each carrying its own `videos` -- guides and every other video that names it, in the same order \/api\/stages\/{key} lists them in.","For a stage\u0027s full field set, or to filter stages independently of an event, use \/api\/stages?event={key}."]},{"method":"GET","path":"\/api\/creators","description":"Content creator collection: who they are, what they make, where to find them.","notes":["A creator is not necessarily a YouTube channel. `hasYoutube` says whether the crawler watches one for them; `links` is where they publish, YouTube included.","`types` is the list of type names -- Guidemaker, Analyst, ... -- a creator carries. A creator can carry several."],"filters":{"q":"free text over name, handle and description","name":"substring match against the name","handle":"exact handle, with or without the @","type":"only creators of this type, by type name, case-insensitive; comma-separated or repeated for several (OR)","hasYoutube":"boolean; whether a YouTube channel is registered for them","sort":"name, priority, id, createdAt (priority puts unranked creators last either way)","order":"asc or desc","page":"integer, 1-based","limit":"integer, capped by AKUP_MAX_PAGE_SIZE"}},{"method":"GET","path":"\/api\/creators\/{key}","description":"One creator with everything: types, links, YouTube channels, and their newest videos.","notes":["{key} is the numeric id, or the handle with or without its @.","`youtube` lists the channels the crawler reads for them, with `lastCrawledAt` so \u0022no videos\u0022 can be told from \u0022not crawled yet\u0022. Empty for a creator who is not on YouTube.","`videos` is the newest 8 of any kind, newest first. The full, filterable list is \/api\/creators\/{key}\/videos."]},{"method":"GET","path":"\/api\/creators\/{key}\/videos","description":"One creator\u0027s stored videos, filtered and paged, each naming the stages it covers.","notes":["Same {key} rule as the item. The response carries the creator\u0027s collection shape under `creator` so a client need not fetch it separately.","Every Arknights video of theirs is stored -- uploads about other games are not -- and each carries a `kind`: `stage` when the crawler could tie it to at least one stage, `general` otherwise (a showcase, a review, a stream).","Each entry\u0027s `stages` lists every stage the video covers, in offset order, with a per-stage `url` that carries `\u0026t=` for a compilation chapter. Empty for a `general` video."],"filters":{"kind":"stage or general; both when unset","title":"substring match against the video title (`q` is an alias)","publishedAfter":"date or datetime; only videos published at or after it","publishedBefore":"date or datetime; only videos published strictly before it. A bare date is midnight UTC, so pass the day after to include a whole day.","code":"only videos linked to a stage under this display code; comma-separated or repeated","sort":"publishedAt, title, durationSeconds, id","order":"asc or desc (default desc)","page":"integer, 1-based","limit":"integer, default 20, capped by AKUP_MAX_PAGE_SIZE"}},{"method":"GET","path":"\/api\/operators","description":"Operator collection, surface fields only: id, name, potentialItemId, tagList, position, rarity, profession, subProfessionId.","filters":{"q":"free text over name and appellation","profession":"WARRIOR, SNIPER, ...; comma-separated or repeated","subProfessionId":"comma-separated or repeated","position":"MELEE or RANGED; comma-separated or repeated","rarity":"TIER_1..TIER_6; comma-separated or repeated","tag":"exact match against one entry of tagList","sort":"name, rarity, profession, subProfessionId, sortIndex, id","order":"asc or desc","page":"integer, 1-based","limit":"integer, capped by AKUP_OPERATOR_MAX_PAGE_SIZE (1000 by default, enough for the whole roster)"}},{"method":"GET","path":"\/api\/operators\/{key}","description":"One operator with everything -- trait, skills, talents included -- plus every video associated with it.","notes":["{key} is the source\u0027s own id (e.g. char_002_amiya), or the internal numeric id.","Add ?raw=1 to also get the untouched source record, minus phases, potentialRanks, favorKeyFrames and allSkillLvlup -- see the note below.","`videos` is empty for an operator nobody has made a video about, and empty everywhere until an operator import and at least one `app:youtube:crawl` have run."]}],"creators":{"description":"A content creator is a person or team making Arknights content. The YouTube channels the video crawler reads belong to creators; a creator may have one, several or none, so \u0022creator\u0022 and \u0022YouTube channel\u0022 are different things in this API.","fields":{"id":"Numeric id. Also what the `creator.id` under a stage\u0027s videos points at.","name":"Display name.","handle":"Lowercase, without the @. Null when they go by name alone. Accepted in place of the id on the item endpoints.","description":"A blurb. Seeded from the YouTube channel description when the creator was registered through a channel, editorial after that.","priority":"Rank in a stage\u0027s video list, 1 first; null for an unranked creator, who sorts after every ranked one.","types":"Type names, alphabetical -- Guidemaker, Analyst, and whatever else has been entered. A creator can have several.","links":"Where to find them: `{type, url, label}` each. `type` is a lowercase word -- youtube, discord, website, twitter, twitch, bilibili are the conventional ones -- for a client to pick an icon by; `label` is optional display text.","hasYoutube":"Whether at least one YouTube channel is registered for them."},"note":"Creators are entered by hand: `bin\/console app:youtube:channel:add` for a YouTube channel (which makes a creator for it), `bin\/console app:creator:add` for everyone else and for editing types and links. Empty until one of them has run."},"maps":{"description":"Every stage in either shape carries `mapCount`: how many map images arknights.wiki.gg has for it, counted by `bin\/console app:stage:maps` from the downloaded \u003Cstage\u003E_map.png files. 1 until that has run.","names":{"1":"\u003Cstem\u003E_map.png","2 or more":"\u003Cstem\u003E_map_1.png .. \u003Cstem\u003E_map_N.png -- the numbered files replace the unnumbered one.","0":"No image on the wiki under the stage\u0027s code or name."},"note":"\u003Cstem\u003E is the display code for nearly every stage (CF-S-1_map_1.png). Where the code is shared -- the Campaign stages are all \u0022Ursus\u0022 or \u0022Yan\u0022, the Stationary Security Service ones all \u0022LT-1\u0022..\u0022LT-8\u0022 -- the wiki uses the stage name with spaces as underscores (Lungmen_Outskirts_map.png)."},"videos":{"description":"Only the item shape carries `videos` and `videosSpecial`: two arrays, both empty for a stage nobody has covered and empty everywhere until `bin\/console app:youtube:crawl` has run. Each entry is one video, flattened, with the creator that made it. Ordered by the creator\u0027s priority (1 first, unranked last), then newest upload first.","split":"The two lists are split on the creator, not the video: a creator carrying the Guidemaker type puts their videos in `videos`, everyone else\u0027s go in `videosSpecial`. A guide and a \u0022zero operators, 100 retries\u0022 clear match the same stage code, and only who made it says which one you are looking at. See `creator.types` on each entry.","fields":{"videoId":"YouTube\u0027s own id, to build an embed URL from.","url":"Ready-to-use watch URL, already carrying `\u0026t=` when the entry has an offset.","startSeconds":"Where in the video this stage starts, or null when the video is about it from the beginning. Filled from the description chapters of compilation videos.","matchedCode":"The stage code the crawler matched on, so a wrong video is traceable to its cause.","source":"title, chapter or manual -- how the link came to exist. A crawl rebuilds the first two and never touches the third.","thumbnails":"Keyed by YouTube\u0027s size name, smallest first. Sizes YouTube does not serve are absent rather than null.","creator":"id, channelId, handle, name, the channel URL, the creator\u0027s priority -- the rank that ordered the list, null for an unranked creator -- and their `types`. `id` is what \/api\/creators\/{key} takes; channelId, handle and url are the YouTube channel the video came from."},"caveat":"A stage code is not unique -- events reuse them, so \u0022TN-1\u0022 is a stage in six separate Boss Rush events -- and a video that names a code is linked to every stage carrying it."},"events":{"description":"Every stage in either shape carries an `events` array: the in-game events it belongs to, oldest run first. A main story stage\u0027s event is its chapter (displayType MAINLINE, undated). Empty for other permanent content -- main theatre, Annihilation, the training and weekly stages -- which belongs to no event, and empty everywhere until `bin\/console app:event:import` (and, for the main story, `app:chapter:import`) has run.","fields":{"eventId":"The event id, e.g. act41side, or a chapter\u0027s zone id, e.g. main_1. This is what `?event=` takes.","name":"Display name, e.g. \u0022When Elegies Are Ashes\u0022, or \u0022Episode 1: Evil Time Part 2\u0022 for a chapter.","type":"The game\u0027s internal category, e.g. TYPE_ACT9D0, MINISTORY, BOSS_RUSH, MAINLINE.","displayType":"SIDESTORY, MINISTORY, BRANCHLINE, BOSS_RUSH, MAINLINE or NONE. The \/api\/events collection only lists SIDESTORY, MINISTORY, BOSS_RUSH and MAINLINE.","startAt":"When the event opened. Null for a main story chapter -- permanent content, not time-boxed.","endAt":"When it closed. Rerun events are dated in the future when the dump is ahead of the live server. Null for a main story chapter.","isReplicate":"Whether this run is a rerun of an earlier event.","source":"zone or stage-id -- how the stage was matched to the event. See the note below.","matchedOn":"The identifier the match was made on, so a pairing that looks wrong is traceable to its cause."},"note":"Neither dump states that a stage belongs to an event; it is derived from two identifiers. `zone` means the stage\u0027s zoneId is one of the event\u0027s zones (act17d5_zone1 -\u003E act17d5), which is where the stage is played. `stage-id` means the stage id is namespaced to the event (act9d0_01 -\u003E act9d0), which is where it came from. The two disagree exactly when an event is being rerun, because a rerun keeps the original run\u0027s stage ids -- so such a stage carries two entries, and `?event=` returns it under either id."},"links":{"description":"Every stage in either shape carries a `links` object: where that stage can be looked at elsewhere. A site is null when it has no page for the stage, and null everywhere until `bin\/console app:link:import` has run.","sites":{"arkrec":"ArkRec\u5c11\u4eba wiki (least-operators clear records). Matched on stageId, so operations ArkRec lists without one -- mostly the dated Annihilation and legacy Contingency Contract entries -- have no link.","stageViewer":"awedtan\u0027s Stage Viewer (map and wave replay). Present for stages that have a levelId, which is what the viewer loads the map from."}},"operators":{"description":"Operator data comes from Kengxxiao\u0027s character_table.json directly (Kengxxiao\/ArknightsGameData_YoStar for Global, the sibling Kengxxiao\/ArknightsGameData for CN-only operators), read by bin\/console app:operator:import -- no third-party wrapper API involved.","dropped":"phases, potentialRanks, favorKeyFrames and allSkillLvlup are per-level stat\/cost progressions, not a description of the operator, and are dropped on import -- not modeled, not kept in the raw leftovers either.","videos":"An operator\u0027s videos are matched by name against video titles, the same way stages are matched by code: see VideoStageMatcher\u0027s relevance test, which operator matching reuses, and OperatorNameIndex for the name-matching algorithm and its known false-positive risk. A video already in youtube_video is checked against a brand new operator immediately on import; app:youtube:crawl keeps matching new videos against every operator afterward.","nameCn":"name_cn is the Chinese name, filled in for every operator by bin\/console app:operator:import --cn-source (Kengxxiao\/ArknightsGameData\u0027s own character_table.json, not the _YoStar one). For an operator CN has and Global has not released yet, name and name_cn are the same string -- there is no English name yet.","lookup":"\/api\/operators\/{key} takes the charId (e.g. char_002_amiya), the internal numeric id, or an exact match on name or name_cn (e.g. Amiya or \u963f\u7c73\u5a05)."}}