API¶
PoracleNG exposes an HTTP API for external tools — PoracleWeb, ReactMap, the Poracle Config UI, and custom integrations — to manage users and tracking, edit DTS templates and configuration, read game data, and inject messages. The processor is a single binary; the whole API is served by the processor on its configured [processor] port (default 3030).
Live, exhaustive reference: /docs and /openapi.json
Every running processor serves an OpenAPI 3.1 document at GET /openapi.json and interactive documentation at GET /docs. Both are generated from the code, so they always match the version you are running, and they list every field, enum, default and error code. These pages explain how the API fits together and give working examples; use /docs on your own server for field-level detail.
Authentication¶
Set an api_secret in the [processor] section of config.toml:
Every request under /api/ must then carry the secret in the X-Poracle-Secret header:
A missing or wrong secret returns 401:
A blank api_secret leaves /api open
If api_secret is empty or unset, the authentication check is skipped and every /api/* endpoint is reachable without a secret — including user deletion, config rewrites, and message delivery. From 5.3 the processor logs a warning at startup when the secret is blank and the effective listen host isn't loopback (this includes the PORACLE_HOST override, so Docker's 0.0.0.0 triggers it); 5.2 gives no warning. Always set a secret on any processor reachable from outside the host, and consider restricting access with ip_whitelist (below) or a firewall. See [processor].
Backward compatibility
An api_secret under [alerter] is still read and copied into [processor] at load time if [processor] api_secret is empty. New configs should use [processor].
IP allow/deny lists¶
[processor] ip_whitelist and ip_blacklist restrict which client IPs may connect. They apply to every route on the port — the API, /health, /metrics, and the scanner webhook receiver (POST /) — so if you set a whitelist, include your scanner's address. The blacklist is checked first; a non-empty whitelist then allows only matching addresses. Rejected clients get a bare 403.
[processor]
ip_whitelist = ["127.0.0.1", "10.0.0.0/8", "2001:db8::/32"]
trusted_proxies = ["172.16.0.0/12"] # only if Poracle sits behind a reverse proxy
- CIDR ranges (5.3+). Entries may be exact IPv4/IPv6 addresses or CIDR ranges. Invalid entries in any of the three lists stop startup with an error naming the entry (5.2 accepted only exact IPs and silently ignored anything else).
trusted_proxies(5.3+). By default no proxy is trusted, so the client IP is always the TCP peer andX-Forwarded-For/X-Real-IPare ignored. If Poracle is behind a reverse proxy (nginx, Traefik, a Docker network) and you rely on the IP lists, list the proxy's address or range here, otherwise every request appears to come from the proxy.
5.2: forwarded headers can be spoofed
In 5.2 every proxy is trusted, so the IP filter believes any X-Forwarded-For header a client sends and the lists can be bypassed. Don't rely on ip_whitelist alone as access control on 5.2; set api_secret and firewall the port.
Full field reference: [processor].
CORS¶
CORS headers (Access-Control-Allow-Origin: *) are sent on every response, and OPTIONS pre-flight requests are answered directly, so browser-based editors can call the API from another origin. The secret is still required.
Public endpoints¶
These do not require X-Poracle-Secret.
| Method | Path | Description |
|---|---|---|
POST |
/ |
Scanner webhook receiver (Golbat / RDM) |
GET |
/health |
Health check, version and capability flags |
GET |
/metrics |
Prometheus metrics |
GET |
/openapi.json |
OpenAPI 3.1 spec for the whole /api surface |
GET |
/docs |
Interactive API documentation (Stoplight Elements, loaded from unpkg.com) |
/debug/pprof (Go profiling)
From 5.3, /debug/pprof/ only exists when [processor] enable_pprof = true (default off), and then requires X-Poracle-Secret like /api. Startup warns if it's enabled with a blank api_secret. Leave it off unless you're diagnosing a performance problem.
In 5.2, /debug/pprof/ is always mounted and not behind the secret. Don't expose a 5.2 processor port directly to the internet; put it behind a reverse proxy that only forwards what you need, or use ip_whitelist.
GET /health¶
{
"status": "healthy",
"version": "5.3.0",
"capabilities": {
"buttons": true,
"snapshots": true,
"autocreate": true,
"tomlDts": true,
"buttonResponseObject": true,
"derivedDtsTypes": true,
"costume": true,
"customMaps": true
}
}
capabilities lets clients detect features without probing endpoints. Treat a missing key as false. A capability means the binary supports a feature; it may still be switched off in config (for example buttons need [snapshots] enabled = true).
| Flag | Meaning |
|---|---|
buttons |
DTS entries can carry interactive buttons[]; GET /api/dts/actions exists |
snapshots |
Per-delivery snapshot store is present (GET /api/snapshots/{messageID}) |
autocreate |
Channel auto-create and /api/autocreate/* are present |
tomlDts |
config/dts/*.toml files are loaded and saved back in TOML |
buttonResponseObject |
Button response_template_inline accepts a JSON object |
derivedDtsTypes |
/api/dts/testdata and /api/dts/enrich understand DTS type names (monsterChanged, incident, questSummary, …) |
costume |
Pokemon and raid tracking rules accept a costume filter (5.3+) |
customMaps |
GET /api/dts/custommaps exists and {{map}} follows PoracleJS semantics (5.3+) |
Errors¶
Most of the API is served through huma, and errors from those endpoints use RFC 9457 application/problem+json:
{
"title": "Unprocessable Entity",
"status": 422,
"detail": "validation failed",
"errors": [
{"message": "expected integer", "location": "body[0].min_iv", "value": "ninety"}
]
}
422means the request failed schema validation (wrong type, missing required field, unknown field on a strict endpoint).400is used for handler-level validation on some older endpoints.401authentication failures keep the legacy{"status":"authError"}body shown above, because they're rejected before huma runs.- The frozen v1 endpoints (
/api/tracking/*,/api/humans/*,/api/profiles/*) still return the old{"status":"error","message":"…"}shape. See Legacy v1 API.
Successful responses fall into three shapes:
- Action endpoints (reloads, enable/disable, deletes, …) return
{"status": "ok"}. - Reads on the original
/api/*endpoints return{"status": "ok", …data}. /api/v2reads and tracking mutations return the resource or diff directly, with nostatusenvelope.
v1 or v2?¶
User, tracking and profile management exists in two versions:
/api/v2— strict, typed and fully documented in/docs. Unknown fields are rejected, "any" is expressed by omitting a field rather than sending a magic number, and errors are problem+json. Use v2 for anything new. Newer features (theincidenttracking type, saved-location update, mutes,ping, user listing and deletion) are v2-only.- v1 (
/api/tracking/*,/api/humans/*,/api/profiles/*) — the original, lenient API. It's frozen and deprecated but still supported: it keeps working, gets no new features, and has no removal date yet.
See Migrating from v1 for an endpoint-by-endpoint mapping.
All other endpoint groups (config, DTS, geofences, summaries, delivery, …) have only one version and live under /api/.
Endpoint groups¶
| Group | Paths | Page |
|---|---|---|
| v2 tracking | /api/v2/humans/{id}/tracking/* |
Tracking (v2) |
| v2 humans & locations | /api/v2/humans, /api/v2/humans/{id}/* |
Humans & locations (v2) |
| v2 profiles, roles & mutes | /api/v2/humans/{id}/profiles, …/roles, …/mutes |
Profiles, roles & mutes (v2) |
| Legacy v1 | /api/tracking/*, /api/humans/*, /api/profiles/* |
Legacy v1 API |
| Config & game data | /api/config/*, /api/masterdata/*, /api/v2/activity, /api/weather, /api/stats/*, /api/geocode/* |
Config & game data |
| DTS editor | /api/dts/*, /api/config/templates |
DTS editor API |
| Geofences & map tiles | /api/geofence/* |
Geofence API |
| Summaries | /api/summaries/* |
Summaries API |
| Delivery, test & commands | /api/deliverMessages, /api/test, /api/command, /api/resolve, /api/snapshots/* |
Delivery, test & commands |
| Auto-create | /api/autocreate/* |
Auto-create API |
| Reload | /api/reload, /api/geofence/reload, /api/dts/reload |
below |
| Validation hook (outbound) | Your URL, called by Poracle | Validation hook |
Reload endpoints¶
All three accept GET or POST and return {"status": "ok"} when done.
| Endpoint | What it reloads |
|---|---|
/api/reload |
Humans and every tracking rule from the database. Geofences and DTS are left as they are. |
/api/geofence/reload |
Geofence files from disk and Koji, rebuilds the spatial index, then reloads humans and tracking from the database. Use after editing fences or rotating a Koji token. |
/api/dts/reload |
DTS templates and partials from config/dts.json, config/dts/ and the bundled fallbacks. Doesn't touch tracking or geofences. Only registered when DTS rendering is available. |
Tracking and human changes made through the API trigger a debounced reload automatically, so you only need /api/reload after editing the database directly.
Upstream reference¶
The PoracleNG repository also has API.md and the v1 → v2 migration guide. Where those disagree with /openapi.json from your running processor, the OpenAPI spec is correct.
Version notes
The OpenAPI spec, /api/v2 and v2 mutes are in 5.2. Items marked 5.3+ on these pages are on the develop branch and will ship in the next release.