← API reference

Admin

Users, tokens, genre-map scrape. Session-only, admin role.

19 of 19 · v0.120.0
GET /admin/users #
Session

List users.

Session-only, admin role. Never reachable with a token.

Responses

200

OK.

application/json

object

Every account on the instance.

users array required
each item
object

An account, as an admin sees it in the user list.

id integer · int64 required
username string required
display_name string | null
role string required

admin or user.

created_at integer · int64 required

Unix seconds.

disabled boolean required

Blocked from signing in; nothing is deleted.

401

No valid session cookie or token. Also returned when a token is presented to a session-only endpoint — the endpoint does not accept tokens at all, so the scope is irrelevant.

application/json

object

Every error body in the API has this shape.

code integer · int32 required

Mirrors the HTTP status.

error string required

Human-readable. Not a stable identifier — do not branch on it.

{
  "code": 401,
  "error": "Authentication required. Log in to access this endpoint."
}
403

Authenticated, but not permitted. Either the token lacks the required scope, or the endpoint needs the admin role. Deliberately not a 401 — re-authenticating will not help.

application/json

object

Every error body in the API has this shape.

code integer · int32 required

Mirrors the HTTP status.

error string required

Human-readable. Not a stable identifier — do not branch on it.

{
  "code": 403,
  "error": "This token does not have the 'write' scope"
}
POST /admin/users #
Session

Create a user.

Session-only, admin role. There is no self-registration — this instance is invite-only by design. The account is created with the user role; promote it with PATCH /admin/users/{id}.

Request body required

application/json

object
username string required
display_name string | null
password string | null

Optional. Without one the account cannot sign in until an admin sets a password with PATCH /admin/users/{id}, but its token works at once.

Responses

201

Created.

application/json

object
user_id integer · int64 required
username string required
token string required

A submit token for the new account. Shown once, never again.

message string required
400

Malformed or rejected input.

application/json

object

Every error body in the API has this shape.

code integer · int32 required

Mirrors the HTTP status.

error string required

Human-readable. Not a stable identifier — do not branch on it.

401

No valid session cookie or token. Also returned when a token is presented to a session-only endpoint — the endpoint does not accept tokens at all, so the scope is irrelevant.

application/json

object

Every error body in the API has this shape.

code integer · int32 required

Mirrors the HTTP status.

error string required

Human-readable. Not a stable identifier — do not branch on it.

{
  "code": 401,
  "error": "Authentication required. Log in to access this endpoint."
}
403

Authenticated, but not permitted. Either the token lacks the required scope, or the endpoint needs the admin role. Deliberately not a 401 — re-authenticating will not help.

application/json

object

Every error body in the API has this shape.

code integer · int32 required

Mirrors the HTTP status.

error string required

Human-readable. Not a stable identifier — do not branch on it.

{
  "code": 403,
  "error": "This token does not have the 'write' scope"
}
409

That username is taken.

application/json

object

Every error body in the API has this shape.

code integer · int32 required

Mirrors the HTTP status.

error string required

Human-readable. Not a stable identifier — do not branch on it.

PATCH /admin/users/{id} #
Session

Change a user's role, reset their password, or disable them.

Session-only, admin role. The last active admin can be neither demoted nor disabled. Everything is checked before anything is written, so a 400 changes nothing.

Parameters

id path required

The user.

integer · int64

Request body required

application/json

object

Absent fields are left alone.

role string | null

admin or user. The last active admin cannot be demoted.

password string | null

Reset the password to this, no current password needed. At least 8 characters.

disabled boolean | null

Block or allow sign-in without deleting anything. You cannot disable yourself, or the last active admin.

Responses

200

Updated. status is updated.

application/json

object

An acknowledgement with nothing else to report.

status names what happened — ok, updated, deleted, cleared, started and so on; the operation says which it sends. A client needs only the HTTP status to know it worked.

status string required
400

Malformed or rejected input.

application/json

object

Every error body in the API has this shape.

code integer · int32 required

Mirrors the HTTP status.

error string required

Human-readable. Not a stable identifier — do not branch on it.

401

No valid session cookie or token. Also returned when a token is presented to a session-only endpoint — the endpoint does not accept tokens at all, so the scope is irrelevant.

application/json

object

Every error body in the API has this shape.

code integer · int32 required

Mirrors the HTTP status.

error string required

Human-readable. Not a stable identifier — do not branch on it.

{
  "code": 401,
  "error": "Authentication required. Log in to access this endpoint."
}
403

Authenticated, but not permitted. Either the token lacks the required scope, or the endpoint needs the admin role. Deliberately not a 401 — re-authenticating will not help.

application/json

object

Every error body in the API has this shape.

code integer · int32 required

Mirrors the HTTP status.

error string required

Human-readable. Not a stable identifier — do not branch on it.

{
  "code": 403,
  "error": "This token does not have the 'write' scope"
}
404

No such resource, or it belongs to another user.

application/json

object

Every error body in the API has this shape.

code integer · int32 required

Mirrors the HTTP status.

error string required

Human-readable. Not a stable identifier — do not branch on it.

DELETE /admin/users/{id} #
Session

Delete a user and everything they own.

Session-only, admin role. You cannot delete yourself, or the last active admin.

Parameters

id path required

The user.

integer · int64

Responses

204

Deleted.

400

Malformed or rejected input.

application/json

object

Every error body in the API has this shape.

code integer · int32 required

Mirrors the HTTP status.

error string required

Human-readable. Not a stable identifier — do not branch on it.

401

No valid session cookie or token. Also returned when a token is presented to a session-only endpoint — the endpoint does not accept tokens at all, so the scope is irrelevant.

application/json

object

Every error body in the API has this shape.

code integer · int32 required

Mirrors the HTTP status.

error string required

Human-readable. Not a stable identifier — do not branch on it.

{
  "code": 401,
  "error": "Authentication required. Log in to access this endpoint."
}
403

Authenticated, but not permitted. Either the token lacks the required scope, or the endpoint needs the admin role. Deliberately not a 401 — re-authenticating will not help.

application/json

object

Every error body in the API has this shape.

code integer · int32 required

Mirrors the HTTP status.

error string required

Human-readable. Not a stable identifier — do not branch on it.

{
  "code": 403,
  "error": "This token does not have the 'write' scope"
}
404

No such resource, or it belongs to another user.

application/json

object

Every error body in the API has this shape.

code integer · int32 required

Mirrors the HTTP status.

error string required

Human-readable. Not a stable identifier — do not branch on it.

GET /admin/tokens #
Session

The caller's API tokens.

Session-only. Token secrets are never returned after issue.

Responses

200

OK.

application/json

object

The caller's tokens. Secrets are never returned after issue.

tokens array required
each item
object

An API token, without its secret.

id integer · int64 required
name string required
scopes string required

As stored: submit, read, write, all, space- or comma-separated.

created_at integer · int64 required

Unix seconds.

last_used_at integer | null · int64

Unix seconds; null for a token never used.

default_chain_id integer | null · int64

Rung 3 of the chain ladder.

imports_are_live boolean required

Whether this client's import submissions are forwarded as live listens.

default_chain_name string | null

The default chain's name.

401

No valid session cookie or token. Also returned when a token is presented to a session-only endpoint — the endpoint does not accept tokens at all, so the scope is irrelevant.

application/json

object

Every error body in the API has this shape.

code integer · int32 required

Mirrors the HTTP status.

error string required

Human-readable. Not a stable identifier — do not branch on it.

{
  "code": 401,
  "error": "Authentication required. Log in to access this endpoint."
}
POST /admin/tokens #
Session

Mint a token.

Session-only. The secret is in this response and nowhere else.

Name it per device — that is what makes revocation meaningful when a phone is lost. default_chain_id is rung 3 of the chain ladder: one token per app makes attribution zero-configuration on the client side.

Request body required

application/json

object
user_id integer | null · int64

Whose token. Defaults to the caller; anyone else's is admin-only, since minting a token for another account is taking it over.

name string required

Name it per device — that is what makes revocation meaningful when a phone is lost.

scopes string

Space- or comma-separated: submit, read, write, or all. None implies another.

default_chain_id integer | null · int64

The chain every listen submitted with this token is attributed to, unless the listen carries better evidence — rung 3 of the chain ladder. One token per app makes attribution zero-configuration on the client side. Must be one of the owner's chains.

imports_are_live boolean

Whether this client's listen_type: "import" submissions are live listens rather than a backfill. Some players (fooyin) label every scrobble import; without this their listens are stored but never forwarded to Last.fm / ListenBrainz. Even when set, only listens from the last 24h are forwarded, so a genuine history import from the same client stays local.

Responses

201

Created.

application/json

object
token string required

The secret. In this response and nowhere else.

name string required
user_id integer · int64 required
message string required
400

An empty name, or a chain that is not the owner's.

application/json

object

Every error body in the API has this shape.

code integer · int32 required

Mirrors the HTTP status.

error string required

Human-readable. Not a stable identifier — do not branch on it.

401

No valid session cookie or token. Also returned when a token is presented to a session-only endpoint — the endpoint does not accept tokens at all, so the scope is irrelevant.

application/json

object

Every error body in the API has this shape.

code integer · int32 required

Mirrors the HTTP status.

error string required

Human-readable. Not a stable identifier — do not branch on it.

{
  "code": 401,
  "error": "Authentication required. Log in to access this endpoint."
}
403

A token for another user, and the caller is not an admin.

application/json

object

Every error body in the API has this shape.

code integer · int32 required

Mirrors the HTTP status.

error string required

Human-readable. Not a stable identifier — do not branch on it.

PATCH /admin/tokens/{id} #
Session

Rename a token or repoint its default chain, without re-issuing it.

Session-only. Fixing the chain never means re-pasting a token into a client. default_chain_id is nullable-and-optional: present-and-null clears it, absent leaves it alone. Any chain id is checked against the owner's own chains.

Parameters

id path required

The token's id, not its secret.

integer · int64

Request body required

application/json

object

Absent fields are left alone.

name string | null
default_chain_id integer | null · int64

Present-and-null clears the chain; absent leaves it alone. Checked against the owner's own chains.

imports_are_live boolean | null

See POST /admin/tokens for what it does.

Responses

200

Updated. status is updated.

application/json

object

An acknowledgement with nothing else to report.

status names what happened — ok, updated, deleted, cleared, started and so on; the operation says which it sends. A client needs only the HTTP status to know it worked.

status string required
400

Malformed or rejected input.

application/json

object

Every error body in the API has this shape.

code integer · int32 required

Mirrors the HTTP status.

error string required

Human-readable. Not a stable identifier — do not branch on it.

401

No valid session cookie or token. Also returned when a token is presented to a session-only endpoint — the endpoint does not accept tokens at all, so the scope is irrelevant.

application/json

object

Every error body in the API has this shape.

code integer · int32 required

Mirrors the HTTP status.

error string required

Human-readable. Not a stable identifier — do not branch on it.

{
  "code": 401,
  "error": "Authentication required. Log in to access this endpoint."
}
404

No such resource, or it belongs to another user.

application/json

object

Every error body in the API has this shape.

code integer · int32 required

Mirrors the HTTP status.

error string required

Human-readable. Not a stable identifier — do not branch on it.

DELETE /admin/tokens/{id} #
Session

Revoke a token.

Session-only. This is the mitigation for a lost device.

Parameters

id path required

The token's id, not its secret.

integer · int64

Responses

200

Revoked. status is revoked.

application/json

object

An acknowledgement with nothing else to report.

status names what happened — ok, updated, deleted, cleared, started and so on; the operation says which it sends. A client needs only the HTTP status to know it worked.

status string required
401

No valid session cookie or token. Also returned when a token is presented to a session-only endpoint — the endpoint does not accept tokens at all, so the scope is irrelevant.

application/json

object

Every error body in the API has this shape.

code integer · int32 required

Mirrors the HTTP status.

error string required

Human-readable. Not a stable identifier — do not branch on it.

{
  "code": 401,
  "error": "Authentication required. Log in to access this endpoint."
}
404

No such resource, or it belongs to another user.

application/json

object

Every error body in the API has this shape.

code integer · int32 required

Mirrors the HTTP status.

error string required

Human-readable. Not a stable identifier — do not branch on it.

POST /admin/tokens/{id}/rotate #
Session

Re-issue a token in place.

Session-only. Same id, name, scopes and chain; new secret, returned once.

Parameters

id path required

The token's id, not its secret.

integer · int64

Responses

200

Rotated.

application/json

object

A re-issued token.

token string required

The new secret, returned once. The old one stops working now.

message string required
401

No valid session cookie or token. Also returned when a token is presented to a session-only endpoint — the endpoint does not accept tokens at all, so the scope is irrelevant.

application/json

object

Every error body in the API has this shape.

code integer · int32 required

Mirrors the HTTP status.

error string required

Human-readable. Not a stable identifier — do not branch on it.

{
  "code": 401,
  "error": "Authentication required. Log in to access this endpoint."
}
404

No such resource, or it belongs to another user.

application/json

object

Every error body in the API has this shape.

code integer · int32 required

Mirrors the HTTP status.

error string required

Human-readable. Not a stable identifier — do not branch on it.

GET /admin/ops #
Session

Engine, sink and source health for this instance.

Session-only, admin role — instance-wide, and the source rows are not scoped to the caller. One request rather than several because the Operations screen polls it while open.

tick.behind is the number that matters: a tick taking longer than its own interval_secs means source polling and the deck are that late. sinks[].skipping_for is set while a service's breaker is open and it is being skipped outright. Neither credentials nor source URLs are returned.

Responses

200

OK.

application/json

object

Engine, sink and source health. Times are Unix seconds.

version string required
uptime_secs integer · int64 required
tick object required

The engine's tick.

interval_secs integer · int64 required

The configured interval — the denominator for everything else here.

ticks integer · int64 required
last_started integer | null · int64
last_duration_ms integer · int64 required
longest_ms integer · int64 required

Worst tick since the process started.

overruns integer · int64 required

Ticks that ran longer than the configured interval.

deferred_listens integer · int64 required

Listens the flush left for the next tick because it ran out of budget. Nonzero means forwarding is behind.

behind boolean required

The last tick took longer than its own interval: source polling and the deck are that late. The number that matters.

sinks array required
each item
object

One forwarding service's circuit breaker.

name string required
failures integer · int32 required

Consecutive failures since the last success.

total_failures integer · int64 required

Since the process started.

total_successes integer · int64 required
last_ok integer | null · int64
last_failure integer | null · int64
last_error string | null

The most recent error, verbatim.

skipping_for integer | null · int64

Seconds left while the breaker is open and the service is being skipped outright.

sources array required

Every user's sources — instance-wide, with no credentials or URLs.

each item
object

One source's liveness, with nothing secret in it.

id integer · int64 required
user_id integer · int64 required
username string required
kind string required
label string required
enabled boolean required
poll_interval_secs integer | null · int64
last_polled_at integer | null · int64
last_error string | null
logs_enabled boolean required

File logging is on, so /admin/logs has something to show.

401

No valid session cookie or token. Also returned when a token is presented to a session-only endpoint — the endpoint does not accept tokens at all, so the scope is irrelevant.

application/json

object

Every error body in the API has this shape.

code integer · int32 required

Mirrors the HTTP status.

error string required

Human-readable. Not a stable identifier — do not branch on it.

{
  "code": 401,
  "error": "Authentication required. Log in to access this endpoint."
}
403

Authenticated, but not permitted. Either the token lacks the required scope, or the endpoint needs the admin role. Deliberately not a 401 — re-authenticating will not help.

application/json

object

Every error body in the API has this shape.

code integer · int32 required

Mirrors the HTTP status.

error string required

Human-readable. Not a stable identifier — do not branch on it.

{
  "code": 403,
  "error": "This token does not have the 'write' scope"
}
GET /admin/logs #
Session

The tail of a log file, filtered.

Session-only, admin role. A log carries usernames, source labels and request paths, so this is deliberately unreachable with an API token — the endpoint does not accept one, so scopes never enter into it.

level means "this and worse", so warn includes errors. matched is what the filter found against shown, so a capped tail cannot be mistaken for the whole answer.

Parameters

lines query

Newest N matching lines. Default 300, at most 2000.

integer
level query

error | warn | info | debug, meaning "this and worse".

string
q query

Substring filter, applied after the level.

string
file query

One of the names from /admin/logs/files; anything else is a 404. Defaults to the one being written.

string

Responses

200

OK.

application/json

object

The newest matching lines of one log file.

file string required
files array required

Every file there is, newest first.

each item
string
matched integer required

How many lines the filter found…

shown integer required

…against how many are shown.

truncated boolean required
lines array required

Oldest first.

each item
string
401

No valid session cookie or token. Also returned when a token is presented to a session-only endpoint — the endpoint does not accept tokens at all, so the scope is irrelevant.

application/json

object

Every error body in the API has this shape.

code integer · int32 required

Mirrors the HTTP status.

error string required

Human-readable. Not a stable identifier — do not branch on it.

{
  "code": 401,
  "error": "Authentication required. Log in to access this endpoint."
}
403

Authenticated, but not permitted. Either the token lacks the required scope, or the endpoint needs the admin role. Deliberately not a 401 — re-authenticating will not help.

application/json

object

Every error body in the API has this shape.

code integer · int32 required

Mirrors the HTTP status.

error string required

Human-readable. Not a stable identifier — do not branch on it.

{
  "code": 403,
  "error": "This token does not have the 'write' scope"
}
404

File logging is off, or no such file.

application/json

object

Every error body in the API has this shape.

code integer · int32 required

Mirrors the HTTP status.

error string required

Human-readable. Not a stable identifier — do not branch on it.

GET /admin/logs/files #
Session

The log files this instance is holding, newest first.

Session-only, admin role. Seven daily files are kept. These names are the only values file accepts elsewhere — a request names one of these, never a path.

Responses

200

OK.

application/json

object
files array required

Newest first.

each item
object
name string required

The only kind of value file accepts elsewhere.

bytes integer · int64 required
401

No valid session cookie or token. Also returned when a token is presented to a session-only endpoint — the endpoint does not accept tokens at all, so the scope is irrelevant.

application/json

object

Every error body in the API has this shape.

code integer · int32 required

Mirrors the HTTP status.

error string required

Human-readable. Not a stable identifier — do not branch on it.

{
  "code": 401,
  "error": "Authentication required. Log in to access this endpoint."
}
403

Authenticated, but not permitted. Either the token lacks the required scope, or the endpoint needs the admin role. Deliberately not a 401 — re-authenticating will not help.

application/json

object

Every error body in the API has this shape.

code integer · int32 required

Mirrors the HTTP status.

error string required

Human-readable. Not a stable identifier — do not branch on it.

{
  "code": 403,
  "error": "This token does not have the 'write' scope"
}
404

File logging is off on this instance.

application/json

object

Every error body in the API has this shape.

code integer · int32 required

Mirrors the HTTP status.

error string required

Human-readable. Not a stable identifier — do not branch on it.

GET /admin/logs/download #
Session

Download one log file whole.

Session-only, admin role. Served private, no-store.

Parameters

file query

One of the names from /admin/logs/files. Defaults to today's.

string

Responses

200

The file.

text/plain

string
401

No valid session cookie or token. Also returned when a token is presented to a session-only endpoint — the endpoint does not accept tokens at all, so the scope is irrelevant.

application/json

object

Every error body in the API has this shape.

code integer · int32 required

Mirrors the HTTP status.

error string required

Human-readable. Not a stable identifier — do not branch on it.

{
  "code": 401,
  "error": "Authentication required. Log in to access this endpoint."
}
403

Authenticated, but not permitted. Either the token lacks the required scope, or the endpoint needs the admin role. Deliberately not a 401 — re-authenticating will not help.

application/json

object

Every error body in the API has this shape.

code integer · int32 required

Mirrors the HTTP status.

error string required

Human-readable. Not a stable identifier — do not branch on it.

{
  "code": 403,
  "error": "This token does not have the 'write' scope"
}
404

File logging is off, or no such file.

application/json

object

Every error body in the API has this shape.

code integer · int32 required

Mirrors the HTTP status.

error string required

Human-readable. Not a stable identifier — do not branch on it.

POST /admin/restart #
Session

Drain and stop, so a supervisor restarts the process.

Session-only, admin role. In-flight requests drain and the engine finishes its current tick before the process exits, so this cannot cut a write in half — it is gentler than the kill an operator reaches for otherwise.

The process exits non-zero (75, EX_TEMPFAIL) deliberately: the supplied systemd unit is Restart=on-failure, so a clean exit would stop the service instead of restarting it. On a host with nothing supervising the process, this is a stop.

Responses

202

Accepted; the drain has started.

application/json

object
status string required

restarting.

note string required
401

No valid session cookie or token. Also returned when a token is presented to a session-only endpoint — the endpoint does not accept tokens at all, so the scope is irrelevant.

application/json

object

Every error body in the API has this shape.

code integer · int32 required

Mirrors the HTTP status.

error string required

Human-readable. Not a stable identifier — do not branch on it.

{
  "code": 401,
  "error": "Authentication required. Log in to access this endpoint."
}
403

Authenticated, but not permitted. Either the token lacks the required scope, or the endpoint needs the admin role. Deliberately not a 401 — re-authenticating will not help.

application/json

object

Every error body in the API has this shape.

code integer · int32 required

Mirrors the HTTP status.

error string required

Human-readable. Not a stable identifier — do not branch on it.

{
  "code": 403,
  "error": "This token does not have the 'write' scope"
}
GET /admin/everynoise #
Session

Genre-map scrape status.

Session-only, admin role.

Responses

200

OK.

application/json

object

What is held, and whether a walk is running.

summary object required

What the local copy currently holds.

genres integer · int64 required
artists integer · int64 required
edges integer · int64 required
pages_scraped integer · int64 required

Genre pages walked, out of genres — the tier 2 progress marker that survives a restart.

last_scraped_at integer | null · int64

Unix seconds of the most recent write, or None when empty.

progress object | null

Null when nothing has run since the process started.

tier string required

map is the genre map, one request; pages is every genre's page, ~6,300 requests at one a second.

mappages
state string required
runningdonefailedcancelled
done integer · int64 required
total integer · int64 required
current string | null

The genre currently being fetched, for a UI that would otherwise show a bar creeping for two hours with nothing to read.

message string | null
started_at integer · int64 required
contact string | null

The admin's address sent in the scraper's User-Agent. Echoed so the field can be pre-filled; it is not a credential.

source string required
401

No valid session cookie or token. Also returned when a token is presented to a session-only endpoint — the endpoint does not accept tokens at all, so the scope is irrelevant.

application/json

object

Every error body in the API has this shape.

code integer · int32 required

Mirrors the HTTP status.

error string required

Human-readable. Not a stable identifier — do not branch on it.

{
  "code": 401,
  "error": "Authentication required. Log in to access this endpoint."
}
403

Authenticated, but not permitted. Either the token lacks the required scope, or the endpoint needs the admin role. Deliberately not a 401 — re-authenticating will not help.

application/json

object

Every error body in the API has this shape.

code integer · int32 required

Mirrors the HTTP status.

error string required

Human-readable. Not a stable identifier — do not branch on it.

{
  "code": 403,
  "error": "This token does not have the 'write' scope"
}
DELETE /admin/everynoise #
Session

Drop the scraped genre map.

Session-only, admin role. The genre map lives in its own database (EVERYNOISE_DB_PATH), kept out of VACUUM INTO backups — those should hold the user's listening, not 6,300 rows of someone else's reference data.

Responses

200

Cleared.

application/json

object
status string required

saved, stopping or cleared.

401

No valid session cookie or token. Also returned when a token is presented to a session-only endpoint — the endpoint does not accept tokens at all, so the scope is irrelevant.

application/json

object

Every error body in the API has this shape.

code integer · int32 required

Mirrors the HTTP status.

error string required

Human-readable. Not a stable identifier — do not branch on it.

{
  "code": 401,
  "error": "Authentication required. Log in to access this endpoint."
}
403

Authenticated, but not permitted. Either the token lacks the required scope, or the endpoint needs the admin role. Deliberately not a 401 — re-authenticating will not help.

application/json

object

Every error body in the API has this shape.

code integer · int32 required

Mirrors the HTTP status.

error string required

Human-readable. Not a stable identifier — do not branch on it.

{
  "code": 403,
  "error": "This token does not have the 'write' scope"
}
409

A scrape is running; stop it first.

application/json

object

Every error body in the API has this shape.

code integer · int32 required

Mirrors the HTTP status.

error string required

Human-readable. Not a stable identifier — do not branch on it.

PUT /admin/everynoise/contact #
Session

Set the admin contact email for the scraper's User-Agent.

Session-only, admin role. The scrape refuses to start without one — a made-up address is worse than none.

Request body required

application/json

object
contact string required

An email address, sent in the scraper's User-Agent so the site's owner can reach whoever is fetching. Empty clears it.

Responses

200

Saved.

application/json

object
status string required

saved, stopping or cleared.

400

Not a plausible address.

application/json

object

Every error body in the API has this shape.

code integer · int32 required

Mirrors the HTTP status.

error string required

Human-readable. Not a stable identifier — do not branch on it.

401

No valid session cookie or token. Also returned when a token is presented to a session-only endpoint — the endpoint does not accept tokens at all, so the scope is irrelevant.

application/json

object

Every error body in the API has this shape.

code integer · int32 required

Mirrors the HTTP status.

error string required

Human-readable. Not a stable identifier — do not branch on it.

{
  "code": 401,
  "error": "Authentication required. Log in to access this endpoint."
}
403

Authenticated, but not permitted. Either the token lacks the required scope, or the endpoint needs the admin role. Deliberately not a 401 — re-authenticating will not help.

application/json

object

Every error body in the API has this shape.

code integer · int32 required

Mirrors the HTTP status.

error string required

Human-readable. Not a stable identifier — do not branch on it.

{
  "code": 403,
  "error": "This token does not have the 'write' scope"
}
POST /admin/everynoise/scrape #
Session

Start a scrape.

Session-only, admin role. Runs when an admin asks and never on a schedule — Every Noise has been frozen since December 2023, so there is nothing to sync.

Tier 1 is one HTTP request and returns every genre with coordinates and colour; genre-level features cost that alone. Tier 2 walks ~6,300 genre pages at 1 req/s — about two hours — for exemplar artists and the adjacency graph. Build on tier 1 first.

A fetch that parses to zero genres is treated as a failure rather than written, or a changed page would silently empty the table. Resume is per page, written in the same transaction as the page's contents, so a crash can never mark a page done with nothing in it. A second concurrent start is refused.

Request body required

application/json

object
tier string required

map (one request) or pages (~6,300, about two hours). pages needs the map first.

Responses

202

Started.

application/json

object
status string required

started.

tier string required

map is the genre map, one request; pages is every genre's page, ~6,300 requests at one a second.

mappages
400

No admin contact set, or an unknown tier.

application/json

object

Every error body in the API has this shape.

code integer · int32 required

Mirrors the HTTP status.

error string required

Human-readable. Not a stable identifier — do not branch on it.

401

No valid session cookie or token. Also returned when a token is presented to a session-only endpoint — the endpoint does not accept tokens at all, so the scope is irrelevant.

application/json

object

Every error body in the API has this shape.

code integer · int32 required

Mirrors the HTTP status.

error string required

Human-readable. Not a stable identifier — do not branch on it.

{
  "code": 401,
  "error": "Authentication required. Log in to access this endpoint."
}
403

Authenticated, but not permitted. Either the token lacks the required scope, or the endpoint needs the admin role. Deliberately not a 401 — re-authenticating will not help.

application/json

object

Every error body in the API has this shape.

code integer · int32 required

Mirrors the HTTP status.

error string required

Human-readable. Not a stable identifier — do not branch on it.

{
  "code": 403,
  "error": "This token does not have the 'write' scope"
}
409

A scrape is already running, or pages was asked for before the map.

application/json

object

Every error body in the API has this shape.

code integer · int32 required

Mirrors the HTTP status.

error string required

Human-readable. Not a stable identifier — do not branch on it.

POST /admin/everynoise/cancel #
Session

Cancel a running scrape.

Session-only, admin role. Progress already written is kept — resume is per page.

Responses

200

Cancelled.

application/json

object
status string required

saved, stopping or cleared.

401

No valid session cookie or token. Also returned when a token is presented to a session-only endpoint — the endpoint does not accept tokens at all, so the scope is irrelevant.

application/json

object

Every error body in the API has this shape.

code integer · int32 required

Mirrors the HTTP status.

error string required

Human-readable. Not a stable identifier — do not branch on it.

{
  "code": 401,
  "error": "Authentication required. Log in to access this endpoint."
}
403

Authenticated, but not permitted. Either the token lacks the required scope, or the endpoint needs the admin role. Deliberately not a 401 — re-authenticating will not help.

application/json

object

Every error body in the API has this shape.

code integer · int32 required

Mirrors the HTTP status.

error string required

Human-readable. Not a stable identifier — do not branch on it.

{
  "code": 403,
  "error": "This token does not have the 'write' scope"
}