POST /api/v1/tidal/connect # Session
Begin connecting a TIDAL account.
Session-only. Returns the URL to open. Authorization Code + PKCE with
S256; the verifier is held in memory for ten minutes and the state
token is single-use.
Scopes asked for are the minimum a push needs — playlists.write,
playlists.read, search.read, user.read — and no collection.* or
playback.
Responses
application/json
object
Where to send the browser.
authorize_url string required
TIDAL's authorize URL, carrying a PKCE S256 challenge and a
single-use state that expires in ten minutes. Open it in a new tab.
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
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."
}
501 TIDAL is not configured on this instance.
application/json
object
Every error body in the API has this shape.
code integer · int32 required
error string required
Human-readable. Not a stable identifier — do not branch on it.
GET /api/v1/tidal/settings # Session
The TIDAL app registration for this server.
Admin only. Never returns the credential itself, the same rule the
Discogs pair and every source credential follow. stored and from_env
are reported separately so the screen can say which is in effect rather
than leaving an operator wondering why an exported variable is being
ignored — a stored value wins.
redirect_uri is the exact string TIDAL must have registered, derived
from PUBLIC_URL so it is the same one the flow will actually send.
Responses
application/json
object
The app registration, without its credentials.
configured boolean required
Stored or from the environment.
stored boolean required
A client id is stored in the database — which wins over the environment.
has_secret boolean required
A stored client id has a stored secret beside it.
from_env boolean required
TAPEDECK_TIDAL_CLIENT_ID and its secret are set.
redirect_uri string required
The exact redirect URI TIDAL must have registered — the one the flow
will send.
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
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
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"
}
PUT /api/v1/connections/spool-forwarding # Session
Set it.
Off by default, and off for every account that predates it. Turning
it on means a play somebody else's deck made — which you were in the
room for, and accepted one at a time — is relayed to your Last.fm and
ListenBrainz like any listen of your own.
A play older than window_days is stored and never relayed even with
the switch on. retro_spool_from_session can offer an evening of any
age and an unanswered invitation can be joined a month later, so
without that bound a single Accept could rewrite a year of a public
history.
Session-only; a token gets 401 and scopes never enter into it. A
scrobble client has no business deciding that another deck may write to
its owner's public record.
Request body required
application/json
object
The switch deciding whether plays accepted out of a Shared Spool are relayed
on to this user's connections, or stored here only.
It lives beside the connections rather than with the rest of Patch because
this is the question "what do my connected services receive", and the answer
is only meaningful next to the list of them.
enabled boolean required
Required, and said explicitly — an absent key is a 400, not a default.
Responses
200 The switch as it now stands.
application/json
object
Whether plays accepted out of a Shared Spool are forwarded.
window_days integer | null · int64
Only plays this recent are relayed, whatever the switch says. Absent
from the answer to a change.
application/json
object
Every error body in the API has this shape.
code integer · int32 required
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
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 /api/v1/connections/lastfm/start # Session
Begin the Last.fm connect flow.
Session-only. Returns a URL to send the browser to.
Responses
application/json
object
Where to send the browser to approve Tapedeck.
token string required
The request token — send it back to …/complete once approved.
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
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."
}
502 The service could not be reached, or refused a token.
application/json
object
Every error body in the API has this shape.
code integer · int32 required
error string required
Human-readable. Not a stable identifier — do not branch on it.
POST /api/v1/connections/lastfm/complete # Session
Finish the Last.fm connect flow.
Session-only. Exchanges the approved request token for a session key, stored
encrypted.
Request body required
application/json
object
token string required
The token …/start returned, after you approved it.
Responses
application/json
object
connected boolean required
400 Not approved yet, or no token.
application/json
object
Every error body in the API has this shape.
code integer · int32 required
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
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."
}
502 The service could not be reached.
application/json
object
Every error body in the API has this shape.
code integer · int32 required
error string required
Human-readable. Not a stable identifier — do not branch on it.
POST /api/v1/connections/librefm/start # Session
Begin the Libre.fm connect flow.
Session-only. GNU FM implements the same AudioScrobbler auth, so this reuses
the Last.fm app credentials.
Responses
application/json
object
Where to send the browser to approve Tapedeck.
token string required
The request token — send it back to …/complete once approved.
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
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."
}
502 The service could not be reached, or refused a token.
application/json
object
Every error body in the API has this shape.
code integer · int32 required
error string required
Human-readable. Not a stable identifier — do not branch on it.