DTS editor API¶
These endpoints let an editor — such as the Poracle Config UI — read, preview, save and test DTS message templates without shell access. All need X-Poracle-Secret. The /api/dts/* endpoints only exist when the DTS renderer started successfully.
Overview¶
| Method | Path | Purpose |
|---|---|---|
GET |
/api/dts/templates |
Template entries with full content |
POST |
/api/dts/templates |
Save one or more entries |
DELETE |
/api/dts/templates |
Delete one entry |
PUT |
/api/dts/templates/file |
Overwrite the Handlebars file behind a templateFile entry |
GET / POST |
/api/dts/reload |
Reload templates and partials from disk |
GET |
/api/config/templates |
Template metadata only (names per type/platform/language) |
GET |
/api/dts/fields |
DTS type names that have field metadata |
GET |
/api/dts/fields/{type} |
Fields, block scopes and snippets for one type |
GET |
/api/dts/partials |
Handlebars partials |
GET |
/api/dts/emoji |
Emoji lookup map |
GET |
/api/dts/custommaps |
Custom maps for {{map}} (5.3+) |
GET |
/api/dts/testdata |
Sample webhook scenarios |
POST |
/api/dts/enrich |
Run a webhook through enrichment and return the template variables |
POST |
/api/dts/render |
Render a stored template with given variables |
POST |
/api/dts/sendtest |
Render a template and deliver it to a user/channel |
GET |
/api/dts/actions |
Available alert-button actions |
Reading templates¶
GET /api/dts/templates¶
Filter with any of type, platform, language, id.
curl -H "X-Poracle-Secret: your-secret" \
"http://localhost:3030/api/dts/templates?type=monster&platform=discord"
{
"status": "ok",
"templates": [
{"id": "1", "type": "monster", "platform": "discord", "language": "", "default": true, "readonly": true,
"template": {"embed": {"title": "{{round iv}}% {{fullName}}"}}},
{"id": "1", "type": "fort-update", "platform": "discord", "language": "", "default": true,
"templateFile": "dts/fort_update.txt", "templateFileContent": "{{#eq fortType 'pokestop'}}…{{/eq}}"}
]
}
readonly: truemarks entries from the bundledfallbacks/. Once you have any editable entry for a type/platform, the fallback entries for that combination are hidden.- Entries that point at an external Handlebars file have
templateFileplus the file's text intemplateFileContent; edit those withPUT /api/dts/templates/file.
GET /api/config/templates¶
Lighter metadata for pickers (e.g. PoracleWeb's template dropdown): available template ids by type, platform and language, without the template bodies. ?includeDescriptions=true adds names and descriptions.
Saving templates¶
POST /api/dts/templates¶
Body is an array of entries. type and platform are required (platform may be empty only for platform-independent types such as help).
curl -X POST -H "X-Poracle-Secret: your-secret" -H "Content-Type: application/json" \
http://localhost:3030/api/dts/templates \
-d '[{"id": "1", "type": "monster", "platform": "discord", "language": "en",
"template": {"embed": {"title": "{{round iv}}% {{fullName}}"}}}]'
How saves land on disk:
- Each entry is written to its own file
config/dts/{type}-{id}[-{platform}][-{language}].json, and removed from wherever it lived before (e.g.config/dts.json), leaving other entries in that file alone. - If the entry currently comes from a TOML file in
config/dts/, it's written back to that TOML file instead, preserving the format. - Saving over a read-only fallback creates an override in
config/dts/; the fallback itself isn't modified.
Changes are live immediately — no reload needed.
DELETE /api/dts/templates?type=&platform=&id=&language=¶
Removes the entry from memory and its source file. type, platform and id are required (400 otherwise). 404 if no such entry; 403 for read-only fallbacks.
PUT /api/dts/templates/file?type=&platform=&id=&language=¶
Replaces the Handlebars text behind a templateFile entry. The file path is looked up from the entry — clients can't supply a path.
curl -X PUT -H "X-Poracle-Secret: your-secret" -H "Content-Type: application/json" \
"http://localhost:3030/api/dts/templates/file?type=fort-update&platform=discord&id=1" \
-d '{"content": "{{#eq fortType '\''pokestop'\''}}…{{/eq}}"}'
{"status": "ok", "templateFile": "dts/fort_update.txt", "backup": "backups/dts/fort_update.txt.bak.2026-10-17_101500"}
The old file is backed up to config/backups/ first. 404 unknown entry, 400 if the entry uses an inline template, 403 for read-only entries.
GET or POST /api/dts/reload¶
Re-reads config/dts.json, config/dts/, partials and the fallbacks. Use it after editing template files by hand. Returns {"status":"ok"}.
Editor helpers¶
GET /api/dts/fields/{type}¶
Everything an editor needs for autocomplete on one DTS type (monster, monsterNoIv, raid, egg, quest, invasion, lure, nest, gym, fort-update, maxbattle, weatherchange, greeting, …; list them with GET /api/dts/fields).
{
"status": "ok",
"type": "monster",
"fields": [
{"name": "fullName", "type": "string", "description": "Name + form combined", "category": "identity", "preferred": true},
{"name": "pokemon_id", "type": "int", "description": "Pokemon ID (webhook)", "category": "identity", "rawWebhook": true, "preferredAlternative": "pokemonId"}
],
"blockScopes": [{"helper": "each", "args": ["pvpGreat"], "iterableFields": ["pvpGreat", "pvpUltra", "pvpLittle"], "fields": ["…"]}],
"snippets": [{"label": "Countdown", "insert": "<t:{{despawnTimestamp}}:R>", "category": "pokemon", "platform": "discord"}]
}
deprecated fields should be hidden or flagged; rawWebhook fields have a nicer enriched equivalent.
GET /api/dts/partials, /api/dts/emoji, /api/dts/custommaps¶
For reproducing server rendering in the browser:
- partials →
{"status": "ok", "partials": {"name": "handlebars source", …}} - emoji → with
?platform=discord:{"status", "platform", "emoji": {key: value}}, the merged map the renderer uses. Withoutplatform:{"status", "defaults", "platforms": {"discord": {…}, "telegram": {…}}}so a UI can show which keys are customised. - custommaps (5.3+) →
{"status": "ok", "maps": {"name": {…}, "name.de": {…}}}fromconfig/customMaps/.{{map}}/{{map2}}tryname.<user language>thenname. Maps load at startup.
GET /api/dts/testdata¶
The named sample webhooks from fallbacks/testdata.json merged with your config/testdata.json — the same scenarios !poracle-test uses.
{
"status": "ok",
"testdata": [{"type": "pokemon", "test": "hundo", "location": "current", "webhook": {"pokemon_id": 149, "…": "…"}}],
"types": {"monster": {"…": "…"}, "monsterChanged": {"…": "…"}}
}
Filter with ?dtsType= (a DTS type name such as monster, invasion, incident; matching entries are tagged with dtsType) or the older ?type= (a raw webhook type such as pokemon, pokestop). types maps every DTS type to its source webhook type.
GET /api/dts/actions¶
Alert-button actions an editor can offer (mute, unsubscribe, redeliver, render, …), with the scopes each accepts, whether a scope is required, and the params it reads:
{"actions": [{"name": "mute", "scopes": ["…"], "required_scope": true, "params": ["duration_min"]}]}
See the buttons section of the DTS docs for how buttons are configured.
Previewing and testing¶
POST /api/dts/enrich¶
Runs a raw webhook through the full enrichment pipeline and returns the variable map templates see.
curl -X POST -H "X-Poracle-Secret: your-secret" -H "Content-Type: application/json" \
http://localhost:3030/api/dts/enrich \
-d '{"type": "pokemon", "language": "en", "platform": "discord",
"webhook": {"pokemon_id": 129, "latitude": 51.28, "longitude": 1.08, "disappear_time": 9999999999,
"individual_attack": 15, "individual_defense": 15, "individual_stamina": 15}}'
{"status": "ok", "variables": {"name": "Magikarp", "fullName": "Magikarp", "iv": 100, "cp": 212, "pvpGreat": ["…"], "…": "…"}}
type is a webhook type (pokemon, raid, quest, pokestop, gym, nest, fort_update, max_battle, …) or, where derivedDtsTypes is advertised in /health, a DTS type name (monsterChanged, incident, questSummary, …). language defaults to en, platform to discord.
POST /api/dts/render¶
Renders a stored template with variables you supply:
{"type": "monster", "id": "1", "platform": "discord", "language": "en", "view": {"fullName": "Magikarp", "iv": 100}}
Returns {"status": "ok", "message": <rendered JSON>}. 404 if no template matches.
POST /api/dts/sendtest¶
Renders a template you supply (string or object, e.g. unsaved editor content) with the given variables and delivers it, so you can see exactly what Discord or Telegram shows.
{
"template": {"embed": {"title": "{{round iv}}% {{fullName}}"}},
"variables": {"fullName": "Magikarp", "iv": 100},
"target": {"id": "123456789012345678", "type": "discord:user"},
"platform": "discord",
"language": "en"
}
target.type defaults to discord:user. Returns {"status": "ok", "message": "sent"}; 400 for a missing template/target or a template that won't compile.
To push a whole webhook through enrichment and rendering to a user, use POST /api/test instead.