HTTP API
Scripts and websites (dashboards, Discord bots, shops) can read and change the server through a JSON API served by FXServer on the game port:
http://<server ip>:<port>/<resource>/v1/<route>Turn it on
The API is off by default. Turn it on in /nay, on the Nayretis page: HTTP API (ApiEnabled). While it is off, every route answers 503 api_disabled. Maximum request size (KB) (ApiMaxBodyKb) bounds request bodies (1024 KB by default).
Tokens
Create tokens in the API tab of /nay (the token is shown once: copy it then) or from the server console:
nay_api_token create <label> <scope...>
nay_api_token list
nay_api_token revoke <id>A token looks like nay_<id>_<secret>. Only its SHA-256 hash is stored. Each token has its scopes, optional allowed addresses (IPv4, IPv6 or CIDR ranges), a request limit per minute and an optional expiry.
Scopes are <resource>.<scope>, with wildcards: nay_car_wash.* gives every route of a script, * gives everything. Each script lists its routes and scopes on its own page, for example Car Wash.
Requests
- Send
Authorization: Bearer <token>. - Bodies are JSON (
Content-Type: application/json) with aContent-Length. Chunked bodies are refused. - After 10 failed authentications within a minute, requests without a valid token from that address are refused for 5 minutes. Valid tokens keep working.
- Behind a reverse proxy, set
nay:apiTrustedProxies(see HTTPS). Otherwise every caller shares the proxy address.
Every answer is JSON with an X-Request-Id header:
{ "ok": true, "data": { } }
{ "ok": false, "error": { "code": "forbidden", "message": "This token does not allow this route", "details": { } } }| Status | Code | Meaning |
|---|---|---|
| 400 | unexpected_body, invalid_json, invalid_request | Body sent to a route without body, body not valid JSON, or malformed Content-Length. |
| 401 | unauthorized | Missing, unknown, revoked or expired token. |
| 403 | forbidden, ip_not_allowed | The token lacks the scope, or the address is not allowed for it. |
| 404 / 405 | not_found, method_not_allowed | Unknown route, or wrong method on a known route. |
| 411 | length_required | Any Transfer-Encoding (chunked body). |
| 413 | payload_too_large | Body over ApiMaxBodyKb. An announced Content-Length over 10 MB is refused before the body is read. |
| 415 | unsupported_media_type | Body that is not application/json. |
| 422 | invalid_request, unknown_parameter, invalid_value | Parameter, query or body failing validation (details.path and details.reason). |
| 429 | rate_limited, too_many_failures | Token over its limit per minute, or address blocked. See Retry-After. |
| 500 | internal_error | The route failed. See the server console. |
| 503 | api_disabled, not_ready | API off, or resource still starting (Retry-After). |
| 504 | timeout | The route did not answer within 10 seconds. It keeps running: a change may still be applied after the 504, so read the state back before retrying. |
nay_lib routes
| Method | Route | Scope | Data |
|---|---|---|---|
| GET | /nay_lib/v1/status | nay.status | Server name, players, max players, framework, inventory, target, Nayretis resources and versions. |
| GET | /nay_lib/v1/players | nay.players | Connected players: id, name, character, identifier, job. |
| GET | /nay_lib/v1/settings/:resource | nay.settings plus <resource>.config or nay.config | Settings of a script with their values. |
| PUT | /nay_lib/v1/settings/:resource/:key | same | Changes a setting. Body { "value": ... }. |
| DELETE | /nay_lib/v1/settings/:resource/:key | same | Resets a setting to its default. |
| GET | /nay_lib/v1/audit | nay.audit | Audit log, 50 rows per page. Query resource, action, actor, from and to (Unix seconds), page. |
Every call that changes something is written to the audit log (api.call, actor api:<token label>).
HTTPS
FXServer only speaks plain HTTP: anyone on the way can read a token sent over it. Put a reverse proxy with a certificate in front of the API and only expose the routes you use. Then tell nay_lib which proxies to trust, so allowed addresses and rate limits apply to the real client address taken from X-Forwarded-For:
set nay:apiTrustedProxies "127.0.0.1"The value is a comma separated list of addresses or CIDR ranges.
nginx:
server {
listen 443 ssl;
server_name api.example.com;
ssl_certificate /etc/letsencrypt/live/api.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/api.example.com/privkey.pem;
location ~ ^/(nay_lib|nay_car_wash)/v1/ {
proxy_pass http://127.0.0.1:30120;
proxy_set_header X-Forwarded-For $remote_addr;
client_max_body_size 1m;
}
}Caddy (certificate obtained automatically):
api.example.com {
@nayretis path_regexp ^/(nay_lib|nay_car_wash)/v1/
reverse_proxy @nayretis 127.0.0.1:30120
}