This section collects conventions that apply across the entire API — who typically consumes it, the URL and encoding rules all endpoints agree on, how pagination works, which custom HTTP headers are supported, and how errors are returned. Read this once before diving into specific endpoints; individual operation references assume you are familiar with everything described here.
The API is shared by three distinct categories of caller, and some endpoints or authorization rules are written with a specific category in mind:
All resources live under a versioned path on a tenant-specific host:
https://api.prod.{tenant}.beat.no/v2/{resource}
{tenant} is the short identifier for the Beat deployment you are
integrating with (for example fabel, skoobe). All current
endpoints are served under /v2/; older versions are not supported.
Both request and response bodies are UTF-8 encoded.
The OAuth 2.0 token endpoint (/v2/oauth2/*) expects
application/x-www-form-urlencoded bodies, as required by the OAuth
spec. Every other /v2/* endpoint exchanges JSON: send
Content-Type: application/json on any POST, PUT, or PATCH and encode
the body with JSON.stringify or your language's equivalent. Do not
rely on the browser's default application/x-www-form-urlencoded for
JSON endpoints — it will be rejected.
id — stringEvery resource has a unique id. Even when the value looks like a
number, it is always a string in both requests and responses. Parse it
as a string on the client side; JavaScript's Number silently loses
precision on large integer values.
date — stringUTC, in the form YYYY-MM-DD (e.g. 1997-07-16).
datetime — stringUTC, in the form YYYY-MM-DDThh:mm:ssTZD (e.g. 1997-07-16T19:20:30Z),
compliant with http://www.w3.org/TR/NOTE-datetime.
Where:
YYYY — four-digit yearMM — two-digit month (01 = January, …)DD — two-digit day of month (01–31)hh — two digits of hour (00–23), 24-hour clockmm — two digits of minute (00–59)ss — two digits of second (00–59)TZD — time zone designator, always ZNo decimal fraction of a second is used, and +hh:mm / -hh:mm
offsets are not accepted — only Z.
url — stringFully qualified URLs only.
List and search results are paginated using HTTP Range headers with
a custom range unit that depends on the resource (for example tracks
on track searches, products on product listings).
Relevant RFC sections:
Defaults: offset 0; page sizes are one of 10, 20, 100, 200,
or 1000 items, resource-dependent.
Note the asymmetric spelling between request and response required by
the RFC: the Range request header uses =, the Content-Range
response header uses a space:
Range: tracks=0-49
Content-Range: tracks 0-49
Key points from RFC 2616 §14.16:
unit SP first-pos "-" last-pos "/" (instance-length | "*").416 Requested Range Not Satisfiable response SHOULD include
Content-Range with * as the range.206 Partial Content response MUST NOT include Content-Range
with *.instance-length is the total number of accessible items in the
collection.A next page exists when instance-length > last-pos + 1. The body may
contain fewer items than last-pos - first-pos + 1, even on 206
responses — Content-Range always reflects the requested range, not
the number of items delivered.
First 20 tracks (the default window):
$ curl "https://api.prod.$TENANT.beat.no/v2/tracks?query=gaga" \
-H "Authorization: Bearer $TOKEN"
HTTP/1.1 206 Partial Content
Accept-Ranges: tracks
Content-Range: tracks 0-19/21 # 21 > 19+1 → next page exists
Second page, items 20–39 inclusive:
$ curl "https://api.prod.$TENANT.beat.no/v2/tracks?query=gaga" \
-H "Authorization: Bearer $TOKEN" \
-H "Range: tracks=20-39"
Out-of-range request:
$ curl "https://api.prod.$TENANT.beat.no/v2/tracks?query=gaga" \
-H "Authorization: Bearer $TOKEN" \
-H "Range: tracks=1000-999"
HTTP/1.1 416 Requested Range Not Satisfiable
Beat defines a small set of optional X-* request headers that let a
client fine-tune what data comes back without changing the URL. All
are optional; defaults are tenant-specific.
X-IncludeRequest additional sub-objects to be embedded in the response. The value is a comma-separated list; valid names are:
release-reviewsrelease-tracksrelease-notesrelease-pricestrack-pricesgroup-releasesgroup-bannersSeveral resources return image references whose concrete sizes are chosen per request: the client sends a header describing the sizes it wants, and the response embeds only those. See each object's Basic response objects section for the accepted size syntax.
X-Release-Cover-SizesSpecifies sizes for release cover images.
X-Artist-Image-SizesSpecifies sizes for artist images.
X-Actor-Image-SizesSpecifies sizes for actor images.
X-Stream-FormatsSelects the stream quality returned for audio/video resources. The value is a comma-separated list of format names. Valid names are:
*/high*/normal*/lowh264/*Supply the values you receive in the streams object of a Track
Extended response; see GET /v2/tracks/{track_id} for details. Used
by GET /v2/streams/online and GET /v2/streams/offline.
X-Stream-ContextStream URLs normally require a user access token and an active
subscription. In some tenant-specific configurations a stream URL can
be fetched based on a different context — for example a promotional
clip attached to an entity. Supply the header as
X-Stream-Context: <entity_type>/<entity_id>.
Response bodies are JSON-encoded.
The root of every response is an object (never a bare array), and keys at the root act as a namespace:
{"tracks": [{"track": {"...": "..."}}]} // no: over-nested
{"tracks": [{"...": "..."}]} // yes
{"title": "value"} // no: missing namespace
{"track": {"title": "value"}} // yes
400 Bad Request — invalid input. The error message indicates which
parameter and why.401 Unauthorized — bad or expired access token. Re-authenticate
the user and retry.403 Forbidden — request rejected by authorization, e.g. missing
role or invalid OAuth signature.404 Not Found — the requested resource does not exist.405 Method Not Allowed — HTTP method not supported on this
endpoint.5xx — server error. Check the status page or file a bug.All non-success responses share the same body shape:
{
"error": "exception",
"error_description": "Human-readable description",
"error_developer": { }
}
error and error_description are always present. error_developer
is an optional object with extra debugging context — safe to log, not
safe to surface to end users.
The API supports Cross-Origin Resource Sharing (CORS) for AJAX requests. Any domain registered as an OAuth application is accepted as an origin.
Plain request from an unregistered origin:
$ curl -i "https://api.beat.no" -H 'Origin: http://example.com'
HTTP/1.1 302 Found
Location: https://developer.beat.no
Request from a registered origin (e.g. the beat.no web app):
$ curl -i "https://api.beat.no" -H 'Origin: http://beat.no'
HTTP/1.1 302 Found
Location: https://developer.beat.no
Access-Control-Allow-Origin: http://beat.no
Access-Control-Expose-Headers: Content-Range, Link, X-RateLimit-Limit, X-RateLimit-Remaining, X-OAuth-Scopes, X-Accepted-OAuth-Scopes
Access-Control-Allow-Credentials: true
CORS preflight:
$ curl -i "https://api.beat.no" -H 'Origin: http://beat.no' -X OPTIONS
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: http://beat.no
Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, X-Release-Cover-Sizes, X-Artist-Image-Sizes, X-Stream-Formats, Authorization, Range
Access-Control-Allow-Methods: GET, POST, PATCH, PUT, DELETE
Access-Control-Expose-Headers: Content-Range, Link, X-RateLimit-Limit, X-RateLimit-Remaining, X-OAuth-Scopes, X-Accepted-OAuth-Scopes
Access-Control-Max-Age: 86400
Access-Control-Allow-Credentials: true
This article walks a partner integration through the full subscription
lifecycle on a Beat tenant: obtaining an app access token, validating
the user's e-mail, creating the user, attaching a payment method,
activating a subscription, and finally stopping or deactivating it.
Every step shows a runnable curl example with the headers a real
client must send. For the full request/response schema of each
endpoint, follow the link in each step's heading to the operation
reference.
Throughout the examples, $TENANT is the tenant identifier (part of
the API host name), and $TOKEN is the currently active access token.
Re-export $TOKEN whenever a new step switches between a client
access token (steps 1–3) and a user access token (steps 4 onwards).
Most subscription-management calls run on behalf of the partner itself
(no end-user context), so authenticate with the client_credentials
grant type using the OAuth 2.0 token endpoint
(POST /v2/oauth2/token).
$ export TENANT=
$ export CLIENT_ID=
$ export CLIENT_SECRET=
$ curl -X POST "https://api.prod.$TENANT.beat.no/v2/oauth2/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
--data-urlencode "grant_type=client_credentials" \
--data-urlencode "client_id=$CLIENT_ID" \
--data-urlencode "client_secret=$CLIENT_SECRET"
Successful response (200 OK):
{
"access_token": "2YotnFZFEjr1zCsicMWpAA",
"expires_in": 3600,
"token_type": "bearer"
}
Store the returned access_token as $TOKEN. Tokens expire — re-issue
when expires_in elapses.
Before creating the user account, verify that the e-mail address
actually belongs to the person signing up. Submit the e-mail via
POST /v2/credentials; the backend stores it as a pending
credential and dispatches a one-time verification code by e-mail.
$ curl -X POST "https://api.prod.$TENANT.beat.no/v2/credentials" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"type": 8,
"credential": "user@example.com"
}'
A successful call returns 202 Accepted with an empty body. Type 8
is the regular user e-mail credential.
Internally this emits a user.credential_verification_requested event
which carries the verification code and is typically forwarded to your
mail delivery system (for example Vero) to hand the code to the user —
either as a code they type back into your signup form, or encoded in a
magic-link URL. You must capture that code from the user before the
next step and pass it as email_token when creating the account.
With the verification code in hand, create the user via
POST /v2/users. The only required fields are email,
email_token, and password; username is strongly recommended to
match the e-mail address.
⚠️ Always use the client-credentials
$TOKENhere. If you callPOST /v2/userswith a user access token, the new account is created as a profile-user of the authenticated user, which will make every subsequent subscription call fail in non-obvious ways.
$ curl -X POST "https://api.prod.$TENANT.beat.no/v2/users" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"username": "user@example.com",
"email": "user@example.com",
"email_token": "<verification code from step 2>",
"password": "<user-chosen password>"
}'
Successful response (201 Created):
{
"user": {
"id": "28392",
"username": "user@example.com"
}
}
Note the id — this is the $USER_ID used in all later steps.
Optional fields such as firstname, lastname, and newsletter can
be supplied in the same body; see the POST /v2/users
reference for the full schema. If the e-mail is already taken, the
response is 409 Conflict.
Steps 5 and 6 (attaching a payment method and listing products) run on
behalf of the user, not the partner, and therefore need a user
access token. Exchange the user's e-mail and password for one using the
password grant type.
$ export USERNAME=user@example.com
$ export PASSWORD=<user-chosen password>
$ curl -X POST "https://api.prod.$TENANT.beat.no/v2/oauth2/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
--data-urlencode "grant_type=password" \
--data-urlencode "client_id=$CLIENT_ID" \
--data-urlencode "client_secret=$CLIENT_SECRET" \
--data-urlencode "username=$USERNAME" \
--data-urlencode "password=$PASSWORD"
Response (200 OK):
{
"access_token": "7924bef2b848a895...",
"expires_in": 3600,
"token_type": "Bearer",
"refresh_token": "b3aa9e0c635923...",
"user_id": "28392"
}
Re-export $TOKEN to the returned access_token and store the
refresh_token securely — it lets the user stay signed in without
re-prompting for the password. See the Authentication
tag for refresh-token handling and OIDC-based sign-in.
Subscriptions are billed against a stored payment method. Attaching one is a two-step flow: create a setup intent, then — once the client has tokenized the card — attach the resulting reference to the user.
Call POST /v2/billing/setupintents with the payment
type (3 for Stripe, 4 for Billwerk / Reepay) and the product the
user intends to subscribe to.
$ curl -X POST "https://api.prod.$TENANT.beat.no/v2/billing/setupintents" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"payment_type": 3,
"product_id": "201"
}'
Response (200 OK):
{
"client_secret": "seti_dadd3b3c4989acb6f0ff1044a50b0974",
"setup_intent": {
"payment_type": 3,
"client_secret": "seti_dadd3b3c4989acb6f0ff1044a50b0974"
}
}
Use the top-level client_secret (the nested
setup_intent.client_secret is deprecated but kept for backwards
compatibility).
Hand this client_secret to the client-side payment SDK — Stripe
Payment/Express/Card Elements for Stripe, or a redirect to the hosted
Billwerk checkout at https://checkout.reepay.com/#/<client_secret>
for Billwerk — to collect card details. The SDK integration itself is
out of scope for this walkthrough; refer to the provider's
documentation. For Billwerk flows, also supply redirect_url and
cancel_url in the setup intent request; the user will be redirected
to one of these when the hosted checkout finishes.
After tokenization Stripe will return a payment-method identifier
(pm_...) on the client side. Do not attach that identifier
directly. Instead, look it up through Beat's backend, keyed by the
setup intent id:
$ curl "https://api.prod.$TENANT.beat.no/v2/billing/paymentmethods?setupintent=seti_dadd3b3c4989acb6f0ff1044a50b0974" \
-H "Authorization: Bearer $TOKEN"
Response (200 OK):
[
{ "reference": "pm_asdf9023jmkasdf02jkasdf" }
]
Some payment types allow the initial-setup payment method to be replaced by a different method downstream; going through Beat's backend ensures you pick up the correct final reference.
For Billwerk flows, the reference is delivered as the
payment_method query parameter on the success-redirect URL instead,
so this lookup call can be skipped.
$ curl -X POST "https://api.prod.$TENANT.beat.no/v2/billing/paymentmethods" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"payment_type": 3,
"reference": "pm_asdf9023jmkasdf02jkasdf"
}'
A 200 OK response means the user's account is now linked to the
payment provider. Any active subscription is also migrated to the new
provider at this point.
Look up the catalog of products this client is allowed to subscribe
users to via GET /v2/products.
$ curl "https://api.prod.$TENANT.beat.no/v2/products" \
-H "Authorization: Bearer $TOKEN"
For large catalogs, paginate with the Range header:
$ curl "https://api.prod.$TENANT.beat.no/v2/products" \
-H "Authorization: Bearer $TOKEN" \
-H "Range: products=20-39"
Pick the product_id you intend to activate.
Activate the chosen product for the user via
POST /v2/users/{user_id}/migrations. Pass
renewable=false to disable auto-renewal.
$ export USER_ID=28392
$ curl -X POST "https://api.prod.$TENANT.beat.no/v2/users/$USER_ID/migrations" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"product_id": "201",
"renewable": true,
"confirmed": true
}'
A 201 Created response means the subscription is live; it should be
visible in Backoffice and in the connected payment provider (Stripe,
Billwerk, etc.).
Inspect a user's current subscriptions via
GET /v2/users/{user_id}/subscriptions.
$ curl "https://api.prod.$TENANT.beat.no/v2/users/$USER_ID/subscriptions" \
-H "Authorization: Bearer $TOKEN"
Response (206 Partial Content):
{
"subscriptions": [
{
"id": "9001",
"product_id": "201",
"state": 3,
"expiry_date": "2026-05-01T00:00:00Z"
}
]
}
Note the id of the subscription you want to stop or deactivate.
Toggle a running subscription's renewal state via
PATCH /v2/users/{user_id}/subscriptions/{subscription_id}.
Pass state=6 to stop (the subscription will expire at the end of the
current period) or state=3 to resume a previously stopped
subscription.
$ export SUBSCRIPTION_ID=9001
$ curl -X PATCH "https://api.prod.$TENANT.beat.no/v2/users/$USER_ID/subscriptions/$SUBSCRIPTION_ID" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{ "state": 6 }'
Response (200 OK):
{
"subscription": {
"expiry_date": "2026-05-01T00:00:00Z",
"next_billing_date": null,
"state": 6
}
}
To end a subscription right away rather than letting it expire
naturally, use
DELETE /v2/users/{user_id}/subscriptions/{subscription_id}.
$ curl -X DELETE "https://api.prod.$TENANT.beat.no/v2/users/$USER_ID/subscriptions/$SUBSCRIPTION_ID" \
-H "Authorization: Bearer $TOKEN"
A 200 OK response confirms the subscription is deactivated.
Returns a paginated list of actors that appear in at least one currently
live release in the catalog, filtered by the supplied role.
The role query parameter is required. It can be any role name known to
the catalog; if no actor currently holds that role, an empty collection
is returned (rather than a 404). Significant roles include:
main-artist for music servicesauthor for audio book servicesPagination follows the standard Range / Content-Range convention with
the actors unit. Include the optional X-Actor-Image-Sizes header to
request actor images at one or more named sizes; when the header is
absent, the image field is omitted from each actor.
Authorization: Any valid bearer token (app-only / visitor tokens are accepted).
| role required | string Role name to filter by (for example |
| X-Actor-Image-Sizes | string Comma-separated list of requested actor image sizes. When omitted, actor images are not included in the response. |
| Range | string Standard range header using the |
{- "actors": [
- {
- "id": "string",
- "name": "string",
- "sort_name": "string",
- "role": "string",
- "image": {
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}
}
]
}Uploads a JPEG image to represent the actor identified by actor_id.
The image replaces any existing image stored for that actor.
The request body must be multipart/form-data with an image field
containing the JPEG file.
Authorization: Editorial admin only.
| actor_id required | string Identifier of the actor whose image is being uploaded. |
| image required | string <binary> JPEG image of the actor. |
{ }Returns the extended artist representation for the given artist_id, including
favourite status (when applicable) and aggregate counts.
Authorization: Any valid bearer token (app-only / visitor tokens are accepted).
| artist_id required | string |
| X-Artist-Image-Sizes | string Header specifies sizes for Artist image basic object. |
{- "artist": {
- "id": "string",
- "name": "string",
- "url": "string",
- "image": {
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}, - "favourite": true,
- "favouritees_count": 0,
- "releases": {
- "top": [
- {
- "id": "string",
- "title": "string",
- "original_title": "string",
- "cover": {
- "release_id": 0,
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}, - "artist": {
- "id": "string",
- "name": "string",
- "url": "string"
}, - "actors": [
- {
- "id": "string",
- "name": "string",
- "sort_name": "string",
- "role": "string",
- "image": {
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}
}
], - "type": "album",
- "favourite": true,
- "url": "string",
- "copyright": "string",
- "release_date": "1997-07-16",
- "language": "string",
- "description": "string",
- "prices": [
- {
- "currency": "BDT",
- "price": 5.9
}
], - "notes": [
- {
- "id": "string",
- "summary": "string",
- "text": "string"
}
], - "reviews": [
- {
- "id": 0,
- "publication": "string",
- "publication_date": "string",
- "title": "string",
- "url": "string",
- "score": {
- "value": "string",
- "scale": {
- "min": 0,
- "max": 0
}, - "formatted": "3/6"
}
}
], - "rating": {
- "value": 5,
- "total": 0
}, - "series": {
- "id": "string",
- "release_number": 0
}, - "ids": {
- "^[a-zA-Z0-9]+$": "string"
}, - "genres": [
- [
- "string"
]
], - "media_available_from": "string",
- "chapters": [
- {
- "title": "string",
- "description": "string",
- "offset": 0
}
], - "technical_protections": [
- "string"
]
}
]
}, - "tracks": {
- "top": [
- {
- "id": "string",
- "title": "string",
- "subtitle": "string",
- "duration": 0,
- "duration_iso": "PT23M15.3S",
- "artist": {
- "id": "string",
- "name": "string",
- "url": "string"
}, - "actors": [
- {
- "id": "string",
- "name": "string",
- "sort_name": "string",
- "role": "string",
- "image": {
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}
}
], - "favourite": true
}
]
}
}
}Toggles the authenticated user's favourite status for the given artist. The operation is idempotent and should always be assumed to succeed by the client.
Clients may include any of the custom image-size headers (e.g.
X-Artist-Image-Sizes, X-Release-Cover-Sizes) to receive the corresponding
image variants in the response.
Server logic: this PATCH is responsible for merging the client-supplied object with the version stored on the server. The server resolves any conflicts; in that case the response contains the merged version of the object. See the User Changes API for details.
Authorization: Logged-in user required.
| artist_id required | string |
| X-Artist-Image-Sizes | string Header specifies sizes for Artist image basic object. |
| X-Base-Change | integer Base change id; defaults to |
| X-Change-Timestamp | string Time of change in UTC; defaults to the current time on the backend. |
| favourite | boolean |
{- "favourite": true
}{- "artist": {
- "id": "string",
- "name": "string",
- "url": "string",
- "image": {
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}, - "favourite": true,
- "favouritees_count": 0,
- "releases": {
- "top": [
- {
- "id": "string",
- "title": "string",
- "original_title": "string",
- "cover": {
- "release_id": 0,
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}, - "artist": {
- "id": "string",
- "name": "string",
- "url": "string"
}, - "actors": [
- {
- "id": "string",
- "name": "string",
- "sort_name": "string",
- "role": "string",
- "image": {
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}
}
], - "type": "album",
- "favourite": true,
- "url": "string",
- "copyright": "string",
- "release_date": "1997-07-16",
- "language": "string",
- "description": "string",
- "prices": [
- {
- "currency": "BDT",
- "price": 5.9
}
], - "notes": [
- {
- "id": "string",
- "summary": "string",
- "text": "string"
}
], - "reviews": [
- {
- "id": 0,
- "publication": "string",
- "publication_date": "string",
- "title": "string",
- "url": "string",
- "score": {
- "value": "string",
- "scale": {
- "min": 0,
- "max": 0
}, - "formatted": "3/6"
}
}
], - "rating": {
- "value": 5,
- "total": 0
}, - "series": {
- "id": "string",
- "release_number": 0
}, - "ids": {
- "^[a-zA-Z0-9]+$": "string"
}, - "genres": [
- [
- "string"
]
], - "media_available_from": "string",
- "chapters": [
- {
- "title": "string",
- "description": "string",
- "offset": 0
}
], - "technical_protections": [
- "string"
]
}
]
}, - "tracks": {
- "top": [
- {
- "id": "string",
- "title": "string",
- "subtitle": "string",
- "duration": 0,
- "duration_iso": "PT23M15.3S",
- "artist": {
- "id": "string",
- "name": "string",
- "url": "string"
}, - "actors": [
- {
- "id": "string",
- "name": "string",
- "sort_name": "string",
- "role": "string",
- "image": {
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}
}
], - "favourite": true
}
]
}
}
}Returns the biography for the given artist, including a short summary, the full text (when available), a link to the full biography and a source indicator.
Authorization: Any valid bearer token (app-only / visitor tokens are accepted).
| artist_id required | string |
{- "bio": {
- "summary": "string",
- "content": "string",
- "url": "string",
- "source": "beat"
}
}Replaces the biography content for the given artist. Pass null in content
to clear the biography.
Authorization: Editorial admin only.
| artist_id required | string |
| content required | string Full text of the artist biography. The controller also accepts |
{- "content": "string"
}{- "bio": {
- "summary": "string",
- "content": "string",
- "url": "string",
- "source": "beat"
}
}Full-text search over the artist catalogue. Matches names (and optionally other
indexed fields) against the supplied query string and returns a paginated list
of lightweight artist records.
The response is always paginated via Range headers; the server replies with
HTTP 206 Partial Content and a Content-Range header describing the slice
returned.
Authorization: Any valid bearer token (app-only / visitor tokens are accepted).
| query required | string Free-text search string. Must be non-empty. |
| Range | string Byte-style range over the |
| X-Artist-Image-Sizes | string Comma-separated list of requested artist image size variants (e.g. |
{- "artists": [
- {
- "id": "string",
- "name": "string",
- "url": "string",
- "image": {
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}, - "favourite": true
}
]
}Returns the current curated list of featured artists. The response is
paginated via Range headers; the default server-side page size is 20.
Authorization: Any valid bearer token (app-only / visitor tokens are accepted).
| X-Artist-Image-Sizes | string Comma-separated list of requested artist image size variants (e.g. |
| Range | string Byte-style range over the |
{- "artists": [
- {
- "id": "string",
- "name": "string",
- "url": "string",
- "image": {
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}, - "favourite": true
}
]
}Replaces the ordered list of featured artists. The server stores the new order and returns the resulting list.
Authorization: Editorial admin only.
| X-Artist-Image-Sizes | string Comma-separated list of requested artist image size variants (e.g. |
required | Array of objects (id_object) Ordered list of artist id references. |
{- "artists": [
- {
- "id": "string"
}
]
}{- "artists": [
- {
- "id": "string",
- "name": "string",
- "url": "string",
- "image": {
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}, - "favourite": true
}
]
}Returns the top releases associated with the given artist, ordered by
popularity. The response is paginated via Range headers.
Results can be filtered by release type via the types query parameter and
by actor role via the role query parameter.
Authorization: Any valid bearer token (app-only / visitor tokens are accepted).
| artist_id required | string |
| types | string Comma-separated list of release types to include. Accepts the shorthand
values
See the Release API for the full list of release types. |
| role | string Filters releases by the artist's actor role on each release. |
| Range | string Byte-style range over the |
| X-Release-Cover-Sizes | integer header specifies sizes for Release cover basic objects. See Basic response object section for details. |
| X-Actor-Image-Sizes | string Header specifies sizes for Actor image objects. |
| X-Includes | string |
{- "releases": [
- {
- "id": "string",
- "title": "string",
- "original_title": "string",
- "cover": {
- "release_id": 0,
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}, - "artist": {
- "id": "string",
- "name": "string",
- "url": "string"
}, - "actors": [
- {
- "id": "string",
- "name": "string",
- "sort_name": "string",
- "role": "string",
- "image": {
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}
}
], - "type": "album",
- "favourite": true,
- "url": "string",
- "copyright": "string",
- "release_date": "1997-07-16",
- "language": "string",
- "description": "string",
- "prices": [
- {
- "currency": "BDT",
- "price": 5.9
}
], - "notes": [
- {
- "id": "string",
- "summary": "string",
- "text": "string"
}
], - "reviews": [
- {
- "id": 0,
- "publication": "string",
- "publication_date": "string",
- "title": "string",
- "url": "string",
- "score": {
- "value": "string",
- "scale": {
- "min": 0,
- "max": 0
}, - "formatted": "3/6"
}
}
], - "rating": {
- "value": 5,
- "total": 0
}, - "series": {
- "id": "string",
- "release_number": 0
}, - "ids": {
- "^[a-zA-Z0-9]+$": "string"
}, - "genres": [
- [
- "string"
]
], - "media_available_from": "string",
- "chapters": [
- {
- "title": "string",
- "description": "string",
- "offset": 0
}
], - "technical_protections": [
- "string"
]
}
]
}Returns the top tracks associated with the given artist, ordered by
popularity. The response is paginated via Range headers.
Results can be filtered by actor role via the role query parameter.
Authorization: Any valid bearer token (app-only / visitor tokens are accepted).
| artist_id required | string |
| role | string Filters tracks by the artist's actor role on each track. |
| Range | string Byte-style range over the |
| X-Release-Cover-Sizes | integer header specifies sizes for Release cover basic objects. See Basic response object section for details. |
| X-Actor-Image-Sizes | string Header specifies sizes for Actor image objects. |
{- "tracks": [
- {
- "id": "string",
- "title": "string",
- "subtitle": "string",
- "duration": 0,
- "duration_iso": "PT23M15.3S",
- "artist": {
- "id": "string",
- "name": "string",
- "url": "string"
}, - "actors": [
- {
- "id": "string",
- "name": "string",
- "sort_name": "string",
- "role": "string",
- "image": {
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}
}
], - "favourite": true
}
]
}API implements OAuth 2.0 protocol for authentication.
Each request to API resources requires an access_token. There are a few ways to get access token depending on client type.
Mobile Apps or Web Apps use authentication by username/password.
grant_type=passwordgrant_type=clone_tokengrant_type=signed_msisdngrant_type=coupongrant_type=verification_codegrant_type=account_usergrant_type=openid_handlegrant_type=client_credentialsIMPORTANT. The duration of access_token, refresh_token, scope is unspecified and can be changed at any time. So clients have to expect any duration at any moment in the future (i.e. data type should be considered as a TEXT in terms of SQL).
Flow: 4.3 Resource Owner Password Credentials Grant.
NOTE: Authentication by user password is an exceptional case and such flow should only be enabled for selected applications. All other the third-party applications MUST use another ways described below.
Request:
POST /v2/oauth2/token HTTP/1.1
Content-Type: application/x-www-form-urlencoded
grant_type=password
&username=<msisdn|email>
&password=<password>
&client_id=APPLICATION_ID
&client_secret=APPLICATION_SECRET
Response:
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache
{
"access_token":"2YotnFZFEjr1zCsicMWpAA",
"expires_in":3600,
"token_type":"example", // bearer
"scope": "" // optional
"refresh_token":"tGzv3JOkF0XG5Qx2TlKWI", // optional
"user_id":"5667asdf" // optional, beat user id - included if access_token generated for
// authenticated user
}
Issue new access token based on signed MSISDN. Used to support Web App's passwordless login for Gakk Media (Robi Web App and others).
SECURITY NOTE: Enabled for Bangladesh phone numbers only at the moment.
SECURITY NOTE: Signature can only be generated by nginx based on specific authorization headers provided by carrier's networks. It makes possible to login to the app without typing of password. See nginx configuration for signature generation procedure.
Request:
POST /v2/oauth2/token HTTP/1.1
Content-Type: application/x-www-form-urlencoded
grant_type=signed_msisdn
&msisdn=8801600000199
&msisdn_signature=87r1uhasdyfp13jskfd
&client_id=APPLICATION_ID
&client_secret=APPLICATION_SECRET
Response:
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache
{
"access_token":"2YotnFZFEjr1zCsicMWpAA",
"token_type":"example",
"expires_in":3600,
"refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",
"user_id":"5667asdf" // beat user id
}
Request:
POST /v2/oauth2/token HTTP/1.1
Content-Type: application/x-www-form-urlencoded
grant_type=coupon
&code=test1
&client_id=APPLICATION_ID
&client_secret=APPLICATION_SECRET
Response:
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache
{
"access_token":"2YotnFZFEjr1zCsicMWpAA",
"token_type":"example",
"expires_in":3600,
"refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",
"user_id":"5667asdf" // beat user id
}
Code can be generated and optionally send to customer by POST v2/codes.
Request:
POST /v2/oauth2/token HTTP/1.1
Content-Type: application/x-www-form-urlencoded
grant_type=verification_code
&msisdn=0029133437595305 // optional, one of msisdn or user_id should present
&user_id=1111 // optional, one of msisdn or user_id should present
&code=1234
&client_id=APPLICATION_ID
&client_secret=APPLICATION_SECRET
Response:
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache
{
"access_token":"2YotnFZFEjr1zCsicMWpAA",
"token_type":"example",
"expires_in":3600,
"refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",
"user_id":"5667asdf" // beat user id
}
Clone user token for the usage by the new client.
The grant_type=clone_token can be used to issue new access_token for the new client based on access_token issued by the different client (both clients are from the same project). The new issued access_token will always have the same associated user_id.
NOTE: Use grant_type=refresh_token to issue access_token for the same client.
Request:
POST /v2/oauth2/token HTTP/1.1
Content-Type: application/x-www-form-urlencoded
grant_type=clone_token
&access_token=2YotnFZFEjr1zCsicMWpAA // access token issued with another client credentials from the same project
&client_id=APPLICATION_ID
&client_secret=APPLICATION_SECRET
Response:
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache
{
"access_token":"087fashf34h7adysfy", // new token with the same user_id
"expires_in":3600,
"token_type":"example", // bearer
"scope": "" // optional
"refresh_token":"dfq4lajw78152345sfga", // optional
"user_id":"5667asdf" // optional, beat user id - included if access_token generated for authenticated user
}
Request:
POST /v2/oauth2/token HTTP/1.1
Content-Type: application/x-www-form-urlencoded
grant_type=account_user
&access_token=<access_token> // access token of one of account users (profiles)
&user_id=<target_user_id> // id of target profile-user within the same account
&client_id=APPLICATION_ID
&client_secret=APPLICATION_SECRET
Response:
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache
{
"access_token":"087fashf34h7adysfy", // new token with the same user_id
"expires_in":3600,
"token_type":"example", // bearer
"scope": "" // optional
"refresh_token":"dfq4lajw78152345sfga", // optional
"user_id":"5667asdf" // optional, beat user id - included if access_token generated for authenticated user
}
This option is used to authenticate by a previously-started OpenID session. The handle is a value that retrieved during the first step of this process. Use this call only after the OpenID callback is finished.
Request:
POST /v2/oauth2/token HTTP/1.1
Content-Type: application/x-www-form-urlencoded
grant_type=openid_handle
&handle=<handle>
&client_id=APPLICATION_ID
&client_secret=APPLICATION_SECRET
Response:
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache
{
"access_token":"2YotnFZFEjr1zCsicMWpAA",
"expires_in":3600,
"token_type":"example", // bearer
"scope": "" // optional
"refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA", // optional\_
"user_id":"5667asdf" // optional, beat user id - included if access_token generated for authenticated user
}
App tokens are used to make requirests to Beat APIs on behalf of an app rather than a user. This can be useful to provide "visitor mode" in the apps.
Request:
POST /v2/oauth2/token HTTP/1.1
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials
&client_id=APPLICATION_ID
&client_secret=APPLICATION_SECRET
Response (the same as for grant_type=password):
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache
{
"access_token":"2YotnFZFEjr1zCsicMWpAA",
"expires_in":3600,
"token_type":"example", // bearer
"scope": "", // optional
// NOTE: no refresh_token field
}
Access tokens have a limited lifetime and can be refreshed when required without asking the user to login again to get new token.
Request:
POST /v2/oauth2/token HTTP/1.1
Content-Type: application/x-www-form-urlencoded
grant_type=refresh_token
&refresh_token=tGzv3JOkF0XG5Qx2TlKWIA
&client_id=APPLICATION_ID
&client_secret=APPLICATION_SECRET
Response (the same as for grant_type=password):
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache
{
"access_token":"2YotnFZFEjr1zCsicMWpAA",
"expires_in":3600,
"token_type":"example", // bearer
"scope": "", // optional
"refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA" // optional
}
Introduced mainly to support Google Play Install Referrer API.
There is an optional parameter to help tracking of install events. When user logs in to the app, client app may specify install_referrer string param provided by Google Play services.
IMPORTANT FOR CLIENTS: App should add install_referrer param only once and must clean it on after successful log in, so repeated log ins should not be tracked/rewarded.
Example:
Request:
POST /v2/oauth2/token HTTP/1.1
Content-Type: application/x-www-form-urlencoded
grant_type=password
&username=johndoe
&password=A3ddj3w
&client_id=APPLICATION_ID
&client_secret=APPLICATION_SECRET,
&install_referrer=u_12345
Response:
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache
{
"access_token":"2YotnFZFEjr1zCsicMWpAA",
"expires_in":3600,
"token_type":"example", // bearer
"scope": "" // optional
"refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA", // optional
"user_id":"5667asdf" // optional, beat user id - included if access_token generated for authenticated user
}
Issues an OAuth 2.0 access_token following the OAuth 2.0
protocol. Each request to other API resources requires an access_token,
which is obtained via one of the grant flows below.
Mobile Apps and Web Apps typically authenticate by username and password.
User Access Tokens:
App Access Token:
Authorization: Public — no credentials required. This endpoint issues bearer tokens; callers present OAuth 2.0 grant credentials (client_id/client_secret, username/password, etc.) in the request body rather than an Authorization header.
| grant_type required | string Type of grant flow being requested (e.g. |
| username | string flows: [password] |
| password | string flows: [password] |
| msisdn | string flows: [signed_msisdn, verification_code] |
| msisdn_signature | string flows: [signed_msisdn] |
| code | string flows: [verification_code, |
| user_id | string flows: [account_user, verification_code (options for verification_code: supply user_id OR msisdn)] |
| access_token | string flows: [clone_token, account_user] |
| handle | string flows: [openid_handle] |
| refresh_token | string flows: [refresh_token] |
| scope | string Optional scope string. |
| client_id | string APPLICATION_ID |
| client_secret | string APPLICATION_SECRET |
{- "access_token": "2YotnFZFEjr1zCsicMWpAA",
- "token_type": "bearer",
- "expires_in": 3600,
- "scope": "read write",
- "refresh_token": "tGzv3JOkF0XG5Qx2TlKWIA",
- "user_id": "5667"
}Starts a new OpenID/partner login session and returns the partner's
authorization URL along with an internal handle. The client redirects
the user to the returned url; after the partner completes authentication
and the callback has fired, the handle can be exchanged for an
access_token via POST /v2/oauth2/token with grant_type=openid_handle.
Authorization: Public — no credentials required. This endpoint bootstraps a partner login flow for an unauthenticated user; the returned handle is later exchanged for a bearer token.
| partner_id required | string ID of the partner to start an auth session with. |
| redirect_url | string URL the user should be redirected to after authentication completes. |
{- "partner_id": "string",
- "redirect_url": "string"
}{- "context": {
- "handle": "string",
- "partner_id": "string",
- "url": "string"
}
}OpenID/OAuth 2.0 redirect callback. The external identity provider redirects
the user's browser here after authentication, passing the auth session
state and (on success) an authorization code. On success the response
redirects the browser to the final destination associated with the
auth session; failures return 400 (bad request) or 404 (unknown or
expired state).
Authorization: Public — no credentials required. This callback is invoked by the user's browser after an external identity provider completes authentication; the state parameter ties the request back to the originating auth session.
| state | string |
| code | string |
{ }Landing page that signals the OpenID auth session has finished. Typically
used by a client as a polling or detection target to know when the browser
has returned from the external identity provider; the client can then
exchange the associated handle for a token via grant_type=openid_handle.
Authorization: Public — no credentials required. This is a terminal landing page for the OpenID login redirect flow and carries no secrets itself.
{- "error": "validation_error",
- "error_description": "The request body failed validation."
}Every operation documents the access level its caller must have. This page explains each access level. For how to obtain a bearer token, see the Authentication API article.
Access levels are not a strict hierarchy. An editorial admin is not
automatically a logged-in user, and a user admin client using the
client_credentials grant has no end-user identity at all. Each endpoint
states plainly which level (or levels) it accepts.
The endpoint can be called without credentials. Used by token endpoints, OpenID login callbacks, and webhooks. Webhook endpoints are public at the transport layer but verify request authenticity out-of-band (e.g. a signed payload from the payment provider).
Prose line: **Authorization:** Public — no credentials required.
A bearer token is required, but it does not need to belong to a logged-in
user. App-only tokens obtained via grant_type=client_credentials (also
called "visitor" tokens) are accepted, as are tokens obtained from any other
grant. Used by browse/search endpoints and other read operations that do
not depend on a user identity.
Prose line: **Authorization:** Any valid bearer token (app-only / visitor tokens are accepted).
The bearer token must belong to an end-user — i.e. it must have been
obtained from one of the user-binding grants (password, clone_token,
verification_code, etc.) and carry a user_id. Used by any endpoint that
operates on "the authenticated user's own" data.
Prose line: **Authorization:** Logged-in user required.
The bearer token must belong to a user that is registered as editorial staff. Used by endpoints that manage catalog content — patching series, uploading cover images, reordering featured artists, and so on.
Prose line: **Authorization:** Editorial admin only.
The caller must use grant_type=client_credentials with a client that is
registered as a user-administration client. Used by partner-integration
endpoints that manage end-user accounts on behalf of the partner (GDPR
deletion, user lookup by email/msisdn, privileged user creation).
Prose line: **Authorization:** User admin client only.
Partner-integration endpoints under /v2/partnerusers/* authenticate with a
shared client-id / client-secret pair sent as headers instead of a bearer
token.
Prose line: **Authorization:** Partner credentials required (X-Auth-Client-Id and X-Auth-Client-Secret).
A small number of endpoints require a bearer token that was issued with a
specific OAuth scope. The scopes in use are statistics and
external-charge. Any underlying grant is accepted as long as the token
carries the scope.
Prose line: **Authorization:** Bearer token with the \statistics` scope.(or`external-charge``).
Used by a single endpoint (GET /v2/lcp/license/status/...) that is
called by Readium LCP servers which cannot present OAuth tokens.
Credentials are provisioned out-of-band with the LCP provider.
Prose line: **Authorization:** HTTP Basic auth (LCP provider credentials).
Some endpoints accept more than one access level (for example, "the user themselves, or a user admin client"). Those operations list the alternatives on one line:
**Authorization:** Logged-in user, or user admin client.
A few endpoints — most notably GET /v2/users — accept different callers
depending on which query parameters are set. These operations show:
**Authorization:** Varies by query parameter — see the parameter descriptions.
and each query parameter that raises the baseline has its own
**Authorization:** line in that parameter's description. A parameter
with no such line inherits the operation's baseline.
Bundles up to 20 subrequests into a single HTTP call. Each subrequest is dispatched
through the regular API router and its response is returned as an entry in the
responses array, in the same order as the input requests.
Typical use cases include initial sign-in sync (fetching featured content and the user's personal data together), periodic refresh of featured content, and post-offline sync that replays queued mutations before fetching updates.
Design inspired by:
Limits and rules:
/v2/batch itself cannot be used as a subrequest URL (no nesting).Authorization,
Content-Type, and configured custom headers. Subrequest values take
precedence, and empty string values are stripped to avoid downstream
validation errors.responses entry and processing continues.For PATCH subrequests, the server merges the client-supplied object with the
server-stored object and resolves conflicts. The response body contains the
merged representation. See the Changes API for details.
Authorization: Any valid bearer token (app-only / visitor tokens are accepted).
required | Array of objects <= 20 items Ordered list of subrequests to execute. Responses are returned in the same order. |
Fetch featured content and the user's personal data in one round trip.
{- "requests": [
- {
- "method": "GET",
- "url": "/v2/releases/featured"
}, - {
- "method": "GET",
- "url": "/v2/users/5667/releases/favourites"
}
]
}{- "responses": [
- {
- "status": 201,
- "headers": {
- "Content-Range": "0-9/11"
}, - "body": {
- "id": "1234"
}
}, - {
- "status": 200,
- "headers": { },
- "body": { }
}, - {
- "status": 400,
- "headers": { },
- "body": {
- "error": "exception",
- "error_description": "Missing `query` parameter"
}
}
]
}Workflow to save card to user account
POST v2/billing/setupintents - get key necessary to collect card details on the client sidePOST v2/billing/paymentmethods - saves card to user accountCreates a setup intent used to collect payment method (card) details on the client side. The card details are then exchanged for a tokenized payment method reference by the client, which can subsequently be attached to the user via the Payment Method API.
Behaviour depends on payment_type:
product_id is required and redirect_url typically
applies.redirect_url and cancel_url may
apply.campaign_code is relevant for Vipps and modifies the agreement
associated with the product.Authorization: Logged-in user required.
| payment_type required | integer User's payment type; see the User API for details. |
| payment_method_subtype | string or null Enum: "card" "bancontact" "ideal" "sepa_debit" Depends on |
| product_id | string or null Required for the Vipps payment type. Creates an agreement tied to the specified product. |
| campaign_code | string or null Relevant for the Vipps payment type. Creates an agreement for the specified product modified by a campaign. |
| redirect_url | string or null URL the user is redirected to after payment details have been collected. Relevant for Vipps, Paystack and Reepay. |
| cancel_url | string or null URL the user is redirected to after cancelling payment. Relevant for Reepay and Paystack. |
object or null Optional arguments that are unique per payment type. |
{- "payment_type": 0,
- "payment_method_subtype": "card",
- "product_id": "string",
- "campaign_code": "string",
- "redirect_url": "string",
- "cancel_url": "string",
- "payment_type_args": {
- "property1": "string",
- "property2": "string"
}
}{- "client_secret": "string",
- "setup_intent": {
- "payment_type": 0,
- "reference": "string",
- "confirmation_url": "string",
- "client_secret": "string"
}
}Returns payment methods associated with the authenticated user.
When the setupintent query parameter is supplied, the response is
scoped to the payment methods that were attached via the referenced
setup intent. When omitted, an empty list is returned.
Authorization: Logged-in user required.
| setupintent | string If set, the response is scoped to payment method references created against the specified setup intent. |
[- {
- "reference": "string"
}
]Saves a payment method (typically a card) to the authenticated user's
account for later use. The reference is the tokenized value returned
by the payment gateway on the client after the setup intent flow has
completed.
Authorization: Logged-in user required.
| payment_type required | integer User's payment type; see the User API for details. |
| reference required | string Card token or reference returned by the payment gateway on the client. |
{- "payment_type": 0,
- "reference": "string"
}{- "error": "error_not_found",
- "error_description": "The requested resource was not found."
}Create a new bookmark for the authenticated user against a track, release, or artist.
The request body must include entity_type and entity_id. The position_type determines
which position fields are required: audio requires position (seconds), while ebook
requires both reader_position_selector (EPUB CFI) and reader_position_ratio (0-1).
Authorization: Logged-in user required.
| X-Change-Timestamp | string Optional client-supplied timestamp for the change; defaults to the server time if omitted. |
Bookmark attributes. entity_type and entity_id are required; position fields depend on position_type.
| entity_type required | string Enum: "track" "release" "artist" Type of entity the bookmark refers to. |
| entity_id required | string Identifier of the entity (track, release, or artist). |
| note | string Optional free-text user note attached to the bookmark. |
| position_type | string Enum: "audio" "ebook" Kind of media position. Defaults to |
| position | integer Required when |
| reader_position_selector | string Required when |
| reader_position_ratio | number <double> [ 0 .. 1 ] Required when |
{- "entity_type": "track",
- "entity_id": "string",
- "note": "string",
- "position_type": "audio",
- "position": 0,
- "reader_position_selector": "epubcfi(/6/2!/0)",
- "reader_position_ratio": 1
}{- "bookmark": {
- "id": "string",
- "entity_type": "track",
- "entity_id": "string",
- "added": "string",
- "note": "string",
- "position_type": "audio",
- "position": 0,
- "reader_position_selector": "epubcfi(/6/2!/0)",
- "reader_position_ratio": 1
}
}Return the bookmark identified by bookmark_id, provided it belongs to the authenticated user.
Authorization: Logged-in user required.
| bookmark_id required | string Identifier of the bookmark to fetch. |
{- "bookmark": {
- "id": "string",
- "entity_type": "track",
- "entity_id": "string",
- "added": "string",
- "note": "string",
- "position_type": "audio",
- "position": 0,
- "reader_position_selector": "epubcfi(/6/2!/0)",
- "reader_position_ratio": 1
}
}Partially update an existing bookmark. All request body fields are optional, but at
least one should be supplied. Position-related fields must be consistent with
position_type: audio requires position (seconds); ebook requires both
reader_position_selector (EPUB CFI) and reader_position_ratio (0-1).
Authorization: Logged-in user required.
| bookmark_id required | string Identifier of the bookmark to update. |
| X-Base-Change | string Identifier of the last change observed by the client, used for optimistic concurrency. |
| X-Change-Timestamp | string Optional client-supplied timestamp for the change; defaults to the server time if omitted. |
Fields to update on the bookmark. All are optional, but at least one should be present.
| note | string Optional free-text user note attached to the bookmark. |
| position_type | string Enum: "audio" "ebook" Kind of media position. Defaults to |
| position | integer Required when |
| reader_position_selector | string Required when |
| reader_position_ratio | number <double> [ 0 .. 1 ] Required when |
{- "note": "string",
- "position_type": "audio",
- "position": 0,
- "reader_position_selector": "epubcfi(/6/2!/0)",
- "reader_position_ratio": 1
}{- "bookmark": {
- "id": "string",
- "entity_type": "track",
- "entity_id": "string",
- "added": "string",
- "note": "string",
- "position_type": "audio",
- "position": 0,
- "reader_position_selector": "epubcfi(/6/2!/0)",
- "reader_position_ratio": 1
}
}Delete the bookmark identified by bookmark_id. The bookmark must belong to the
authenticated user.
Authorization: Logged-in user required.
| bookmark_id required | string Identifier of the bookmark to delete. |
| X-Change-Timestamp | string Optional client-supplied timestamp for the change; defaults to the server time if omitted. |
{- "error": "error_not_found",
- "error_description": "The requested resource was not found."
}Returns the campaign matching the given utm_campaign code, optionally scoped to a specific product.
At most one campaign is returned, wrapped in the campaigns array for consistency with the featured-campaigns endpoint.
Authorization: Any valid bearer token (app-only / visitor tokens are accepted).
| utm_campaign required | string The campaign code (UTM campaign identifier) to look up. |
| product_id | string Optional product identifier used to disambiguate campaigns that exist for multiple products. |
| Range | string Optional byte-style range header; included for consistency with paginated endpoints. |
{- "campaigns": [
- {
- "id": "string",
- "product_id": "string",
- "utm_campaign": "string",
- "rebate_price": 0,
- "rebate_interval": 0,
- "rebate_interval_unit": "string",
- "trial_interval": 0,
- "trial_interval_unit": "DAY",
- "fixed_trial_end_date": "string"
}
]
}Returns the set of campaigns currently marked as featured for the product.
The response can be paginated using the Range request header.
Authorization: Any valid bearer token (app-only / visitor tokens are accepted).
| Range | string Optional byte-style range header used for pagination (e.g. |
{- "campaigns": [
- {
- "id": "string",
- "product_id": "string",
- "utm_campaign": "string",
- "rebate_price": 0,
- "rebate_interval": 0,
- "rebate_interval_unit": "string",
- "trial_interval": 0,
- "trial_interval_unit": "DAY",
- "fixed_trial_end_date": "string"
}
]
}Returns the charges associated with the given entity type and one or more entity IDs for the authenticated user.
Authorization: Any valid bearer token (app-only / visitor tokens are accepted).
| entity_type | string Enum: "coupon" "release" "campaign" "track" The type of entity the charges are attached to. |
| entity_id | string One or more entity IDs. Use commas to separate multiple IDs in the string. Max: 1000 IDs. |
{- "charges": [
- {
- "entity_type": "string",
- "entity_id": "string",
- "state": "string"
}
]
}Create a one-time charge for an entity such as a track, release, coupon, campaign, or balance top-up.
In most cases this is called with a user or visitor token. A charge can also be created on behalf of another user by setting reason to external_charge and authenticating with a token that has the external-charge scope; in that case the request body must include the target user_id.
Authorization: Varies by request body — see the reason parameter.
| reason required | string Enum: "offlining" "coupon" "purchase" "campaign" "external_charge" "vipps_initial_charge" "vipps_renew" The reason for the charge. If set to Authorization: Baseline for this operation is any valid
bearer token. |
| entity_type required | string Enum: "track" "release" "coupon" "campaign" "balance" The type of entity being charged for. |
| entity_id | string The ID of the given entity type (for example |
| payment_type | integer Payment method identifier. Use 3 for Stripe; see the |
| source | string May be required for some payment types (for example, a Stripe token). |
string Email address, used when charging an unauthorized user. | |
| recipient_name | string Recipient username, used in the email template. |
| message | string Personal message included in the email template. |
| amount | integer Charge amount. |
| unit | string Enum: "XCR" "EUR" Unit of the charge amount. |
{- "reason": "offlining",
- "entity_type": "release",
- "entity_id": "123",
- "payment_type": 3,
- "source": "string",
- "email": "string",
- "recipient_name": "string",
- "message": "string",
- "amount": 0,
- "unit": "XCR"
}{- "id": "string"
}Cancel a charge by transitioning it to the cancelled state. Only charges with reason external_charge can be cancelled.
Authorization: Bearer token with the external-charge scope.
| charge_id required | integer The ID of the charge to cancel. |
Lists charges created with reason=external_charge for the given user,
optionally filtered by entity.
Authorization: Bearer token with the external-charge scope.
| user_id required | integer |
| entity_type required | string Enum: "coupon" "release" "campaign" "track" "balance" |
| entity_id | string Optional. Filter by a specific entity ID. |
{- "charges": [
- {
- "id": "string",
- "entity_type": "string",
- "entity_id": "string",
- "state": "paid"
}
]
}Looks up a coupon by its code and reports whether it is valid for redemption.
valid flag on the returned coupon indicates whether it can currently be redeemed.POST /v2/users/{user_id}/coupons/redemptions.Authorization: Any valid bearer token (app-only / visitor tokens are accepted).
| code required | string The coupon code to look up. |
| product_id | string Optional product identifier. When supplied, the lookup is restricted to coupons that apply to the given product; other matches are filtered out. |
| Range | string Standard pagination range header. |
| X-Coupon-Offer-Image-Sizes | string Comma-separated image size tokens (for example |
{- "coupons": [
- {
- "id": "string",
- "code": "string",
- "interval": 6,
- "interval_unit": "MONTH",
- "valid": true,
- "used": true,
- "created": "string",
- "product_id": "string",
- "payment_state": 0,
- "payment_updated": "string",
- "balance_unit": "string",
- "balance_amount": 0,
- "renewable": true,
- "offer_id": "string",
- "name": "3 month membership",
- "image": {
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}
}
]
}Generates a new coupon (gift card) for the authenticated user based on a specific offer.
The offer_id must refer to an offer returned by GET /v2/coupons/offers?type={type}.
Authorization: Any valid bearer token (app-only / visitor tokens are accepted).
| offer_id required | string Identifier of the offer to generate the coupon from. See |
{- "offer_id": "1234"
}{- "coupon": {
- "id": "string",
- "code": "string",
- "interval": 6,
- "interval_unit": "MONTH",
- "valid": true,
- "used": true,
- "created": "string",
- "product_id": "string",
- "payment_state": 0,
- "payment_updated": "string",
- "balance_unit": "string",
- "balance_amount": 0,
- "renewable": true,
- "offer_id": "string",
- "name": "3 month membership",
- "image": {
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}
}
}Lists available coupon offers (gift card offers) for the requested type.
Each offer describes an image, the subscription product it grants, and optionally a price and interval. The typical gift-card lifecycle is:
POST /v2/coupons with offer_id.GET /v2/users/{user_id}/coupons?type=giftcard.POST /v2/users/{user_id}/charges with entity_type=coupon and entity_id={coupon_code}.POST /v2/users/{user_id}/coupons/redemptions with the coupon code.The optional X-Coupon-Offer-Image-Sizes header (for example w50,h200) selects which image sizes are returned on the offer image object. When the header is omitted, the image object is returned empty.
Authorization: Any valid bearer token (app-only / visitor tokens are accepted).
| type required | string The type of offer to list. Only |
| Range | string Standard pagination range header. |
| X-Coupon-Offer-Image-Sizes | string Comma-separated image size tokens (for example |
{- "offers": [
- {
- "id": "string",
- "name": "3 month membership",
- "tagline": "string",
- "type": "giftcard",
- "price": 89000,
- "original_price": 0,
- "interval": 6,
- "interval_unit": "MONTH",
- "expiry_interval": 0,
- "expiry_interval_unit": "DAY",
- "image": {
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}
}
]
}Returns a paginated feed of global catalogue events — publications, favouriting activity and similar occurrences — ordered most recent first.
Unlike /v2/users/{user_id}/events, this feed is not personalised: it
surfaces events relevant to the whole audience rather than a specific
user's subscriptions or social graph.
The response is paginated via the standard Range / Content-Range
headers and always returns HTTP 206 Partial Content.
Authorization: Any valid bearer token (app-only / visitor tokens are accepted).
| X-Actor-Image-Sizes | string Comma-separated list of requested image sizes for actor avatars. |
| X-Artist-Image-Sizes | string Comma-separated list of requested image sizes for artist images. |
| X-Release-Cover-Sizes | string Comma-separated list of requested cover sizes for releases and release groups. |
| Range | string Standard HTTP range header used for pagination (e.g. |
{- "events": [
- {
- "id": "string",
- "title": "Album of the week",
- "created": "string",
- "source_type": "user",
- "source": {
- "id": "string",
- "firstname": "string",
- "lastname": "string",
- "username": "string",
- "favourite": true,
- "favouritees_count": 0,
- "favourite_users_count": 0,
- "featureset": { }
}, - "action_id": "string",
- "target_type": "user",
- "target": {
- "id": "string",
- "firstname": "string",
- "lastname": "string",
- "username": "string",
- "favourite": true,
- "favouritees_count": 0,
- "favourite_users_count": 0,
- "featureset": { }
}
}
]
}Returns the subset of the supplied entity_id list that the authenticated
user has marked as a favourite, for the given entity_type. Entity IDs
that are not in the user's favourites are omitted from the response; as a
consequence, the favourited field on each returned item is always true.
Use this endpoint as a batch lookup to determine which of a known set of entity IDs the user has favourited.
Authorization: Logged-in user required.
| entity_type required | string Enum: "artist" "release" "release-group" "track" "user" Type of the entities to look up. |
| entity_id required | string Example: entity_id=1,2,3 Comma-separated list of entity IDs to test against the user's favourites. A maximum of 1000 IDs may be supplied per request. |
{- "favourites": [
- {
- "entity_type": "artist",
- "entity_id": "string",
- "favourited": true
}
]
}Returns feature flags for the authenticated user.
The response varies depending on the entity_type query parameter:
entity_type is omitted, the endpoint returns the global features
associated with the user and their active subscription.entity_type is provided, the endpoint returns features scoped to
the supplied entities (for example, release-level access flags such as
has_online_access or has_offline_access). In this mode,
entity_id is required.name filter can be used together with entity_type to
restrict the response to specific feature names.Entity-scoped lookups bypass the discoverable-shop filter: if a caller knows an entity ID, the feature is returned even when the entity is not otherwise visible in the shop.
Authorization: Any valid bearer token (app-only / visitor tokens are accepted).
| entity_type | string Enum: "release" "device" Type of the entities to look up features for. When present,
|
| entity_id | Array of strings Comma-separated list of entity IDs to look up features for. Required
when |
| name | string Comma-separated list of feature names to filter the response by.
Only meaningful when |
{- "features": [
- {
- "entity_id": "string",
- "entity_type": "release",
- "name": "quota",
- "enabled": true,
- "properties": {
- "expiry_date": "2022-02-22 22:22:22"
}
}
]
}The Integrations API is a collection of endpoints implementing specifications from Partners.
This is used to propagate business events from the partner to Beat.
Each partner endpoint has a subresource under /v2/integrations/
Receives an incoming webhook event from Stripe and dispatches it to the
internal Stripe integration handler. A 200 response is always returned on
successful processing to acknowledge receipt, as required by the Stripe
webhook contract.
See the Stripe webhooks documentation for the event payload schema and delivery semantics.
Authorization: Public — no credentials required. Request authenticity is verified
via the Stripe-Signature header, which is validated against the
configured webhook signing secret; unauthenticated callers are rejected by
signature validation.
{- "error": "validation_error",
- "error_description": "The request body failed validation."
}Receives an incoming webhook event from the Reepay billing provider and
dispatches it to the internal Reepay integration handler. A 200 response
is always returned on successful processing to acknowledge receipt, as
required by the Reepay webhook contract.
See the Reepay API reference for the event payload schema and delivery semantics.
Authorization: Public — no credentials required. Request authenticity is verified
by recomputing the Reepay webhook signature from the signature,
timestamp, and id fields carried inside the JSON body (not via an
HTTP header); requests whose signature does not match the configured
webhook secret are rejected.
{- "error": "validation_error",
- "error_description": "The request body failed validation."
}Receives an incoming webhook event from the Paystack billing provider and
dispatches it to the internal Paystack integration handler. A 200
response is always returned on successful processing to acknowledge
receipt, as required by the Paystack webhook contract.
See the Paystack webhook documentation for the event payload schema and delivery semantics.
Authorization: Public — no credentials required. Request authenticity is
verified by recomputing the Paystack webhook signature from the request
body and comparing it against the X-Paystack-Signature HTTP header;
requests whose signature does not match the configured webhook secret are
rejected.
{- "error": "validation_error",
- "error_description": "The request body failed validation."
}Returns a paginated list of all layouts available to the authenticated user.
Use the Range header (items=start-end) to request a page. Responses use 206 Partial Content
with Content-Range indicating the returned slice and total count.
Authorization: Logged-in user required.
| Range | string Range header in the form |
{- "layouts": [
- {
- "id": "string",
- "name": "string",
- "region": "string",
- "product_id": "string",
- "profile_type": "string",
- "sections": [
- {
- "position": 0,
- "link_type": "string",
- "link_value": "string",
- "style": "image_large",
- "banner_group_id": "string"
}
]
}
]
}Returns a single layout resolved either by numeric id or by one of the predefined aliases
(for example home or podcasts). Layouts describe the composition of sections rendered
on a given screen.
Authorization: Any valid bearer token (app-only / visitor tokens are accepted). An authenticated end-user may receive a personalised layout.
| id required | string Enum: "*" "home" "podcasts" Numeric layout id, or one of the predefined aliases ( |
{- "layout": {
- "id": "string",
- "name": "string",
- "region": "string",
- "product_id": "string",
- "profile_type": "string",
- "sections": [
- {
- "position": 0,
- "link_type": "string",
- "link_value": "string",
- "style": "image_large",
- "banner_group_id": "string"
}
]
}
}Updates a layout identified by its numeric id. Supports renaming the layout and replacing its list of sections wholesale.
Authorization: Editorial admin only.
| id required | integer Numeric layout id. |
| name | string New human-readable name for the layout. |
| product_id | string or null Deprecated |
| region | string or null Deprecated |
| profile_type | string or null Deprecated |
Array of objects (layout_sections) Replaces all current layout sections with the provided list. |
{- "name": "string",
- "product_id": "string",
- "region": "string",
- "profile_type": "string",
- "sections": [
- {
- "position": 0,
- "link_type": "string",
- "link_value": "string",
- "style": "image_large",
- "banner_group_id": "string"
}
]
}{- "layout": {
- "id": "string",
- "name": "string",
- "region": "string",
- "product_id": "string",
- "profile_type": "string",
- "sections": [
- {
- "position": 0,
- "link_type": "string",
- "link_value": "string",
- "style": "image_large",
- "banner_group_id": "string"
}
]
}
}Returns the list of conditions that control when a given layout is served (for example based on user region, product, or profile type).
Authorization: Logged-in user required.
| id required | integer Numeric layout id. |
{- "conditions": [
- {
- "region": "string",
- "product_id": "string",
- "profile_type": "string"
}
]
}Replaces the full list of conditions attached to a layout. Conditions determine the audience (region, product, profile type) that the layout should be served to.
Authorization: Editorial admin only.
| id required | integer Numeric layout id. |
Array of objects (layout_condition) Full replacement list of conditions for the layout. |
{- "conditions": [
- {
- "region": "string",
- "product_id": "string",
- "profile_type": "string"
}
]
}{- "conditions": [
- {
- "region": "string",
- "product_id": "string",
- "profile_type": "string"
}
]
}Generates a Readium LCP license for the authenticated user to export the given release.
The request is subject to a per-user rate window (configured by readiumlcp.limit.window_days / readiumlcp.limit.count). Exceeding the window returns 403 with error_code=export_limit_reached.
Authorization: Logged-in user required.
| release_id required | integer Release id. |
| purpose required | string Value: "export" |
| password required | string non-empty |
{- "purpose": "export",
- "password": "string"
}{ }CORS preflight for POST /v2/releases/{release_id}/lcp/license. Returns
the Access-Control-Allow-* headers needed by browser clients before
issuing the actual request.
| release_id required | integer Release id. |
{- "error": "error_not_found",
- "error_description": "The requested resource was not found."
}Validates that a specific user currently has access to an LCP-protected release. This endpoint is intended to be polled by the Readium LCP status service (or an equivalent LCP provider component) to determine whether a previously issued license should remain active.
The endpoint does not return a body. A 204 No Content response indicates that the user is still entitled to the release; a non-2xx response indicates that access should be considered revoked or otherwise unavailable. The access check goes through the same catalog and entitlement validation used when originally issuing a license.
A license-status event is dispatched for every call, regardless of outcome, so that access checks can be audited.
Authorization: HTTP Basic auth (LCP provider credentials).
| release_id required | integer Identifier of the LCP-protected release whose access is being validated. |
| user_id required | integer Identifier of the user whose access to the release is being validated. |
Identical semantics to GET on the same path, but the response body is omitted. Useful for LCP status probes that only need to inspect the status code and response headers.
Authorization: HTTP Basic auth (LCP provider credentials).
| release_id required | integer Identifier of the LCP-protected release whose access is being validated. |
| user_id required | integer Identifier of the user whose access to the release is being validated. |
Standard CORS preflight handler for the LCP license status endpoint. No authentication is required for the preflight itself.
| release_id required | integer Identifier of the LCP-protected release. |
| user_id required | integer Identifier of the user. |
{ }Complete a password reset previously initiated through POST /v2/passwords/requests by presenting the one-time security code that was delivered to the user by SMS or e-mail, together with the new password to set.
The user is identified by either msisdn or email — exactly one must be supplied, and the value must match the one used when the reset was initiated. The server verifies that the supplied code matches the one stored for the pending reset and that the new password meets the configured strength and length requirements; on success the account password is updated.
Authorization: Any valid bearer token (app-only / visitor tokens are accepted), since the endpoint is intended to be callable from unauthenticated sign-in forms. The security code delivered during the initiate step, not the bearer token, is what proves the caller controls the account.
Exactly one of msisdn or email must be provided and must match the identifier used when the reset was initiated. Backend behaviour:
code is checked against the one stored for the pending
reset request created by POST /v2/passwords/requests.| msisdn | string Phone number (MSISDN) of the account whose password is being reset. Mutually exclusive with |
string E-mail address of the account whose password is being reset. Mutually exclusive with | |
| code | string Security code received by SMS or e-mail from the preceding |
| password | string New password to set on the account. Must satisfy the configured minimum length and strength requirements. |
{- "msisdn": "string",
- "email": "string",
- "code": "string",
- "password": "string"
}{- "error": "error_not_found",
- "error_description": "The requested resource was not found."
}Start the password reset flow for a user identified by either their msisdn or their email. The server generates a one-time security code and dispatches it through the appropriate channel: an SMS to the phone number, or a password reset link containing the code to the e-mail address.
The caller must supply exactly one of msisdn or email; supplying both is rejected with 400 Bad Request. For privacy reasons the response is the same whether or not a matching account exists — callers should assume success whenever a 201 status is returned.
The code returned (or delivered) by this endpoint is the value that must subsequently be presented to POST /v2/passwords together with the new password to complete the reset.
Clients with the return-password-code scope may additionally set return=true to have the generated code returned in the response body instead of (or in addition to) being delivered through the normal channel. This is intended for trusted integrations that handle delivery themselves, such as partner onboarding flows. Requests that set return=true without the required scope are rejected with 403 Forbidden.
Authorization: Any valid bearer token (app-only / visitor tokens are accepted) for the default flow, since the endpoint is intended to be callable from unauthenticated sign-in forms. Setting return=true additionally requires a bearer token with the return-password-code scope; otherwise the request is rejected with 403 Forbidden.
Exactly one of msisdn or email must be provided. Backend behaviour:
msisdn is provided, the security code is delivered by SMS.email is provided, a password reset link containing the code
is delivered by e-mail.return=true is set, the generated code is returned in the
response body rather than being delivered to the end user. This
requires the return-password-code scope.| msisdn | string Phone number (MSISDN) of the account to reset. Mutually exclusive with |
string E-mail address of the account to reset. Mutually exclusive with | |
| return | boolean Defaults to |
{- "msisdn": "string",
- "email": "string",
- "return": true
}{- "code": "email-token or sms-code"
}Access to products limited to given access_token/client_id, for instance:
Returns a single product, identified by its product ID.
The set of products visible to the caller depends on the authenticated
token (end-user, partner, or Beat). See the Product schema for details.
Authorization: Any valid bearer token (app-only / visitor tokens are accepted).
| product_id required | string |
{- "product": {
- "id": "string",
- "name": "string",
- "description": "string",
- "surface_id": "string",
- "type": "string",
- "recurring_price": 0,
- "recurring_interval": 0,
- "recurring_interval_unit": "DAY",
- "trial_price": 0,
- "trial_interval": 0,
- "trial_interval_unit": "DAY",
- "lock_interval": 0,
- "lock_interval_unit": "DAY",
- "items": [
- {
- "grants": "subscription",
- "type": "recurring",
- "unit": "string",
- "amount": 0
}
]
}
}Returns the products available to the authenticated caller.
The visible set depends on the token used (end-user, partner, or Beat);
see the Product schema for scoping details. The response is paginated
and supports standard Range headers.
Authorization: Any valid bearer token (app-only / visitor tokens are accepted).
| Range | string |
{- "products": [
- {
- "id": "string",
- "name": "string",
- "description": "string",
- "surface_id": "string",
- "type": "string",
- "recurring_price": 0,
- "recurring_interval": 0,
- "recurring_interval_unit": "DAY",
- "trial_price": 0,
- "trial_interval": 0,
- "trial_interval_unit": "DAY",
- "lock_interval": 0,
- "lock_interval_unit": "DAY",
- "items": [
- {
- "grants": "subscription",
- "type": "recurring",
- "unit": "string",
- "amount": 0
}
]
}
]
}Returns the authenticated user's playback/reading progress records.
Can be filtered to a specific entity (or list of entities) by supplying
entity_type together with entity_id. Results are ordered by the
changed field in descending order (most recently updated first), so
this endpoint is also useful for finding the latest played entity.
Authorization: Logged-in user required.
| entity_type | string Enum: "track" "release" Restrict results to progress on entities of this type. Must be supplied together with |
| entity_id | string Example: entity_id=1,2,3 A single entity id, or a comma-separated list of ids. Must be supplied together with |
| Range | string Standard pagination range header (e.g. |
{- "progresses": [
- {
- "id": "string",
- "entity_type": "track",
- "entity_id": "string",
- "changed": "string",
- "position_type": "audio",
- "stop_position": 0,
- "reader_position_selector": "epubcfi(/6/2!/0)",
- "reader_position_ratio": 1
}
]
}Records playback (or reading) progress for the authenticated user on a given entity.
Tolerates conflicts with existing progress: if a progress record already
exists for the same user and entity, that record is updated in place with
the new stop_position (or ebook reader position) and changed
timestamp. In other words, this endpoint performs an upsert.
Authorization: Logged-in user required.
| entity_type required | string Enum: "track" "release" Type of the entity the progress refers to. |
| entity_id required | string Identifier of the entity the progress refers to. |
| changed required | string <Y-m-d H:i:s> Time of the most recent |
| position_type | string Enum: "ebook" "audio" Kind of position being reported. Defaults to |
| stop_position | integer Required if |
| reader_position_selector | string Required if |
| reader_position_ratio | number <double> [ 0 .. 1 ] Required if |
{- "entity_type": "track",
- "entity_id": "string",
- "changed": "string",
- "position_type": "ebook",
- "stop_position": 0,
- "reader_position_selector": "epubcfi(/6/2!/0)",
- "reader_position_ratio": 1
}{- "progress": {
- "id": "string",
- "entity_type": "track",
- "entity_id": "string",
- "changed": "string",
- "position_type": "audio",
- "stop_position": 0,
- "reader_position_selector": "epubcfi(/6/2!/0)",
- "reader_position_ratio": 1
}
}Returns a single progress record belonging to the authenticated user.
Authorization: Logged-in user required.
| progress_id required | string Identifier of the progress record to fetch. |
{- "progress": {
- "id": "string",
- "entity_type": "track",
- "entity_id": "string",
- "changed": "string",
- "position_type": "audio",
- "stop_position": 0,
- "reader_position_selector": "epubcfi(/6/2!/0)",
- "reader_position_ratio": 1
}
}Updates an existing progress record owned by the authenticated user with
a new position and changed timestamp. The target entity is not changed
by this endpoint.
Authorization: Logged-in user required.
| progress_id required | string Identifier of the progress record to update. |
| changed required | string <Y-m-d H:i:s> Time of the most recent |
| position_type | string Enum: "ebook" "audio" Kind of position being reported. Defaults to |
| stop_position | integer Required if |
| reader_position_selector | string Required if |
| reader_position_ratio | number <double> [ 0 .. 1 ] Required if |
{- "changed": "string",
- "position_type": "ebook",
- "stop_position": 0,
- "reader_position_selector": "epubcfi(/6/2!/0)",
- "reader_position_ratio": 1
}{- "progress": {
- "id": "string",
- "entity_type": "track",
- "entity_id": "string",
- "changed": "string",
- "position_type": "audio",
- "stop_position": 0,
- "reader_position_selector": "epubcfi(/6/2!/0)",
- "reader_position_ratio": 1
}
}Deletes a progress record owned by the authenticated user.
Authorization: Logged-in user required.
| progress_id required | string Identifier of the progress record to delete. |
{- "error": "error_not_found",
- "error_description": "The requested resource was not found."
}Returns the authenticated user's streaming/download quotas and current
consumption. Each quota entry describes an access window (quota_start
to quota_end) along with the seconds allowed, used, and remaining, and
flags indicating whether unlimited access, streaming, and downloads are
permitted.
Authorization: Logged-in user required.
{- "quotas": [
- {
- "quota_start": "string",
- "quota_end": "string",
- "available_seconds": 0,
- "used_seconds": 0,
- "quota_seconds": 0,
- "unlimited_access": true,
- "streaming_access": true,
- "download": true,
- "source": "string"
}
]
}Returns the authenticated user's ratings scoped to a single entity. The
response is paginated using the standard Range/Content-Range headers.
Only entity_type=release is currently supported by this endpoint.
Authorization: Logged-in user required.
| entity_type required | string Value: "release" Example: entity_type=release Type of the entity to look up ratings for. Only |
| entity_id required | string Identifier of the entity (release) whose ratings should be returned. |
| Range | string Standard |
{- "ratings": [
- {
- "id": "string",
- "value": 5,
- "note": "string",
- "entity_type": "release",
- "entity_id": "release_id, track_id or artist_id"
}
]
}Creates a new rating owned by the authenticated user for the given
entity. The value is a 0-5 star score and an optional free-text note
may be attached.
Authorization: Logged-in user required.
| X-Change-Timestamp | string Optional client-supplied timestamp used for change tracking. |
| entity_type required | string Enum: "track" "release" "artist" Kind of entity being rated. |
| entity_id required | string corresponds to |
| value required | integer Rating score, 0-5 stars. |
| note | string Optional free-text note attached to the rating. |
{- "entity_type": "track",
- "entity_id": "track_id, release_id, or artist_id",
- "value": 0,
- "note": "string"
}{- "rating": {
- "id": "string",
- "value": 5,
- "note": "string",
- "entity_type": "release",
- "entity_id": "release_id, track_id or artist_id"
}
}Returns a single rating belonging to the authenticated user.
Authorization: Logged-in user required.
| rating_id required | integer Identifier of the rating to fetch. |
{- "rating": {
- "id": "string",
- "value": 5,
- "note": "string",
- "entity_type": "release",
- "entity_id": "release_id, track_id or artist_id"
}
}Updates the value and/or note on an existing rating owned by the
authenticated user. All request body fields are optional, but at least
one should be present.
Authorization: Logged-in user required.
| rating_id required | integer Identifier of the rating to update. |
| X-Change-Timestamp | string Optional client-supplied timestamp used for change tracking. |
All request parameters are optional, but at least one should be present
| value | integer New rating score, 0-5 stars. |
| note | string New free-text note attached to the rating. |
{- "value": 0,
- "note": "string"
}{- "rating": {
- "id": "string",
- "value": 5,
- "note": "string",
- "entity_type": "release",
- "entity_id": "release_id, track_id or artist_id"
}
}Deletes a rating owned by the authenticated user.
Authorization: Logged-in user required.
| rating_id required | integer Identifier of the rating to delete. |
| X-Change-Timestamp | string Optional client-supplied timestamp used for change tracking. |
{- "error": "error_not_found",
- "error_description": "The requested resource was not found."
}Returns a single release by id.
Set X-Include: release-prices (and other release-* values) to include additional fields in the response.
Examples:
/v2/releases/100/v2/releases/9788242180711?ns=isbnAuthorization: Any valid bearer token (app-only / visitor tokens are accepted).
| release_id required | integer Release id when no |
| ns | string Identifier namespace. Supported values: |
| X-Release-Cover-Sizes | integer header specifies sizes for Release cover basic objects. See Basic response object section for details. |
| X-Actor-Image-Sizes | string Header specifies sizes for Actor image objects. |
| X-Include | Array of strings Specify which additional sub-objects to include in a response. The value is a comma-separated list of object names. Valid names are:
|
{- "release": {
- "id": "string",
- "title": "string",
- "original_title": "string",
- "cover": {
- "release_id": 0,
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}, - "artist": {
- "id": "string",
- "name": "string",
- "url": "string"
}, - "actors": [
- {
- "id": "string",
- "name": "string",
- "sort_name": "string",
- "role": "string",
- "image": {
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}
}
], - "type": "album",
- "favourite": true,
- "favourites_count": 0,
- "url": "string",
- "copyright": "string",
- "release_date": "1997-07-16",
- "language": "string",
- "description": "string",
- "prices": [
- {
- "currency": "BDT",
- "price": 5.9
}
], - "notes": [
- {
- "id": "string",
- "summary": "string",
- "text": "string"
}
], - "reviews": [
- {
- "id": 0,
- "publication": "string",
- "publication_date": "string",
- "title": "string",
- "url": "string",
- "score": {
- "value": "string",
- "scale": {
- "min": 0,
- "max": 0
}, - "formatted": "3/6"
}
}
], - "rating": {
- "value": 5,
- "total": 0
}, - "series": {
- "id": "string",
- "release_number": 0,
- "name": "string",
- "description": "string",
- "releases": [
- {
- "id": "string",
- "title": "string",
- "original_title": "string",
- "cover": {
- "release_id": 0,
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}, - "artist": {
- "id": "string",
- "name": "string",
- "url": "string"
}, - "actors": [
- {
- "id": "string",
- "name": "string",
- "sort_name": "string",
- "role": "string",
- "image": {
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}
}
], - "type": "album",
- "favourite": true,
- "url": "string",
- "copyright": "string",
- "release_date": "1997-07-16",
- "language": "string",
- "description": "string",
- "prices": [
- {
- "currency": "BDT",
- "price": 5.9
}
], - "notes": [
- {
- "id": "string",
- "summary": "string",
- "text": "string"
}
], - "reviews": [
- {
- "id": 0,
- "publication": "string",
- "publication_date": "string",
- "title": "string",
- "url": "string",
- "score": {
- "value": "string",
- "scale": {
- "min": 0,
- "max": 0
}, - "formatted": "3/6"
}
}
], - "rating": {
- "value": 5,
- "total": 0
}, - "series": {
- "id": "string",
- "release_number": 0
}, - "ids": {
- "^[a-zA-Z0-9]+$": "string"
}, - "genres": [
- [
- "string"
]
], - "media_available_from": "string",
- "chapters": [
- {
- "title": "string",
- "description": "string",
- "offset": 0
}
], - "technical_protections": [
- "string"
]
}
]
}, - "tracks": [
- {
- "id": "string",
- "title": "string",
- "subtitle": "string",
- "duration": 0,
- "duration_iso": "PT23M15.3S",
- "artist": {
- "id": "string",
- "name": "string",
- "url": "string"
}, - "actors": [
- {
- "id": "string",
- "name": "string",
- "sort_name": "string",
- "role": "string",
- "image": {
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}
}
], - "favourite": true,
- "url": "string",
- "release": {
- "id": "string",
- "title": "string",
- "original_title": "string",
- "cover": {
- "release_id": 0,
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}, - "artist": {
- "id": "string",
- "name": "string",
- "url": "string"
}, - "actors": [
- {
- "id": "string",
- "name": "string",
- "sort_name": "string",
- "role": "string",
- "image": {
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}
}
], - "type": "album",
- "favourite": true,
- "url": "string",
- "copyright": "string",
- "release_date": "1997-07-16",
- "language": "string",
- "description": "string",
- "prices": [
- {
- "currency": "BDT",
- "price": 5.9
}
], - "notes": [
- {
- "id": "string",
- "summary": "string",
- "text": "string"
}
], - "reviews": [
- {
- "id": 0,
- "publication": "string",
- "publication_date": "string",
- "title": "string",
- "url": "string",
- "score": {
- "value": "string",
- "scale": {
- "min": 0,
- "max": 0
}, - "formatted": "3/6"
}
}
], - "rating": {
- "value": 5,
- "total": 0
}, - "series": {
- "id": "string",
- "release_number": 0
}, - "ids": {
- "^[a-zA-Z0-9]+$": "string"
}, - "genres": [
- [
- "string"
]
], - "media_available_from": "string",
- "chapters": [
- {
- "title": "string",
- "description": "string",
- "offset": 0
}
], - "technical_protections": [
- "string"
]
}, - "prices": [
- {
- "currency": "BDT",
- "price": 5.9
}
], - "streams": [
- {
- "id": "string",
- "type": "string"
}
]
}
], - "ids": {
- "^[a-zA-Z0-9]+$": "string"
}, - "genres": [
- [
- "string"
]
], - "chapters": [
- {
- "title": "string",
- "description": "string",
- "offset": 0
}
]
}
}Favourite / unfavourite a release.
Assume the operation is always a success.
Add any custom HTTP headers (as for the GET request, e.g. X-Release-Cover-Sizes, X-Actor-Image-Sizes) to receive the corresponding data in the response.
Server logic:
IMPORTANT: The PATCH request is responsible for merging the object received from the client with the object stored on the server. The server resolves conflicts if there are any. The response will contain the merged version of the object in that case. See the User Changes API for details.
Authorization: Logged-in user required.
| release_id required | integer |
| X-Base_Change | integer Base change id. Defaults to 0 server-side. |
| X-Change-Timestamp | string Time of change in UTC. Defaults to the current server time. |
| X-Release-Cover-Sizes | integer header specifies sizes for Release cover basic objects. See Basic response object section for details. |
| X-Actor-Image-Sizes | string Header specifies sizes for Actor image objects. |
| X-Include | Array of strings Specify which additional sub-objects to include in a response. The value is a comma-separated list of object names. Valid names are:
|
Fields to patch. Only favourite is currently supported by the
server and must be present; any other keys in the body are ignored.
| favourite required | boolean Whether the release should be marked as a favourite for the authenticated user. |
{- "favourite": true
}{- "release": {
- "id": "string",
- "title": "string",
- "original_title": "string",
- "cover": {
- "release_id": 0,
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}, - "artist": {
- "id": "string",
- "name": "string",
- "url": "string"
}, - "actors": [
- {
- "id": "string",
- "name": "string",
- "sort_name": "string",
- "role": "string",
- "image": {
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}
}
], - "type": "album",
- "favourite": true,
- "favourites_count": 0,
- "url": "string",
- "copyright": "string",
- "release_date": "1997-07-16",
- "language": "string",
- "description": "string",
- "prices": [
- {
- "currency": "BDT",
- "price": 5.9
}
], - "notes": [
- {
- "id": "string",
- "summary": "string",
- "text": "string"
}
], - "reviews": [
- {
- "id": 0,
- "publication": "string",
- "publication_date": "string",
- "title": "string",
- "url": "string",
- "score": {
- "value": "string",
- "scale": {
- "min": 0,
- "max": 0
}, - "formatted": "3/6"
}
}
], - "rating": {
- "value": 5,
- "total": 0
}, - "series": {
- "id": "string",
- "release_number": 0,
- "name": "string",
- "description": "string",
- "releases": [
- {
- "id": "string",
- "title": "string",
- "original_title": "string",
- "cover": {
- "release_id": 0,
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}, - "artist": {
- "id": "string",
- "name": "string",
- "url": "string"
}, - "actors": [
- {
- "id": "string",
- "name": "string",
- "sort_name": "string",
- "role": "string",
- "image": {
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}
}
], - "type": "album",
- "favourite": true,
- "url": "string",
- "copyright": "string",
- "release_date": "1997-07-16",
- "language": "string",
- "description": "string",
- "prices": [
- {
- "currency": "BDT",
- "price": 5.9
}
], - "notes": [
- {
- "id": "string",
- "summary": "string",
- "text": "string"
}
], - "reviews": [
- {
- "id": 0,
- "publication": "string",
- "publication_date": "string",
- "title": "string",
- "url": "string",
- "score": {
- "value": "string",
- "scale": {
- "min": 0,
- "max": 0
}, - "formatted": "3/6"
}
}
], - "rating": {
- "value": 5,
- "total": 0
}, - "series": {
- "id": "string",
- "release_number": 0
}, - "ids": {
- "^[a-zA-Z0-9]+$": "string"
}, - "genres": [
- [
- "string"
]
], - "media_available_from": "string",
- "chapters": [
- {
- "title": "string",
- "description": "string",
- "offset": 0
}
], - "technical_protections": [
- "string"
]
}
]
}, - "tracks": [
- {
- "id": "string",
- "title": "string",
- "subtitle": "string",
- "duration": 0,
- "duration_iso": "PT23M15.3S",
- "artist": {
- "id": "string",
- "name": "string",
- "url": "string"
}, - "actors": [
- {
- "id": "string",
- "name": "string",
- "sort_name": "string",
- "role": "string",
- "image": {
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}
}
], - "favourite": true,
- "url": "string",
- "release": {
- "id": "string",
- "title": "string",
- "original_title": "string",
- "cover": {
- "release_id": 0,
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}, - "artist": {
- "id": "string",
- "name": "string",
- "url": "string"
}, - "actors": [
- {
- "id": "string",
- "name": "string",
- "sort_name": "string",
- "role": "string",
- "image": {
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}
}
], - "type": "album",
- "favourite": true,
- "url": "string",
- "copyright": "string",
- "release_date": "1997-07-16",
- "language": "string",
- "description": "string",
- "prices": [
- {
- "currency": "BDT",
- "price": 5.9
}
], - "notes": [
- {
- "id": "string",
- "summary": "string",
- "text": "string"
}
], - "reviews": [
- {
- "id": 0,
- "publication": "string",
- "publication_date": "string",
- "title": "string",
- "url": "string",
- "score": {
- "value": "string",
- "scale": {
- "min": 0,
- "max": 0
}, - "formatted": "3/6"
}
}
], - "rating": {
- "value": 5,
- "total": 0
}, - "series": {
- "id": "string",
- "release_number": 0
}, - "ids": {
- "^[a-zA-Z0-9]+$": "string"
}, - "genres": [
- [
- "string"
]
], - "media_available_from": "string",
- "chapters": [
- {
- "title": "string",
- "description": "string",
- "offset": 0
}
], - "technical_protections": [
- "string"
]
}, - "prices": [
- {
- "currency": "BDT",
- "price": 5.9
}
], - "streams": [
- {
- "id": "string",
- "type": "string"
}
]
}
], - "ids": {
- "^[a-zA-Z0-9]+$": "string"
}, - "genres": [
- [
- "string"
]
], - "chapters": [
- {
- "title": "string",
- "description": "string",
- "offset": 0
}
]
}
}Lists available variants of a given book — e.g. if a book is available as both an ebook and an audio book, both are included.
Authorization: Any valid bearer token (app-only / visitor tokens are accepted).
| id required | string Release id. |
{- "releases": [
- {
- "id": "string",
- "type": "album"
}
]
}Returns a paginated list of bookmarks for the given release (entity_type release). See also the Bookmarks API.
Authorization: Logged-in user required.
| release_id required | integer |
| Range | string |
{- "bookmarks": [
- {
- "id": "string",
- "entity_type": "track",
- "entity_id": "string",
- "added": "string",
- "note": "string",
- "position_type": "audio",
- "position": 0,
- "reader_position_selector": "epubcfi(/6/2!/0)",
- "reader_position_ratio": 1
}
]
}Returns the curated list of featured releases for the current service instance.
Response is paginated via the Range / Content-Range headers.
Authorization: Any valid bearer token (app-only / visitor tokens are accepted).
| X-Release-Cover-Sizes | integer header specifies sizes for Release cover basic objects. See Basic response object section for details. |
| X-Actor-Image-Sizes | string Header specifies sizes for Actor image objects. |
| Range | string |
| X-Include | Array of strings Specify which additional sub-objects to include in a response. The value is a comma-separated list of object names. Valid names are:
|
{- "releases": [
- {
- "id": "string",
- "title": "string",
- "original_title": "string",
- "cover": {
- "release_id": 0,
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}, - "artist": {
- "id": "string",
- "name": "string",
- "url": "string"
}, - "actors": [
- {
- "id": "string",
- "name": "string",
- "sort_name": "string",
- "role": "string",
- "image": {
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}
}
], - "type": "album",
- "favourite": true,
- "url": "string",
- "copyright": "string",
- "release_date": "1997-07-16",
- "language": "string",
- "description": "string",
- "prices": [
- {
- "currency": "BDT",
- "price": 5.9
}
], - "notes": [
- {
- "id": "string",
- "summary": "string",
- "text": "string"
}
], - "reviews": [
- {
- "id": 0,
- "publication": "string",
- "publication_date": "string",
- "title": "string",
- "url": "string",
- "score": {
- "value": "string",
- "scale": {
- "min": 0,
- "max": 0
}, - "formatted": "3/6"
}
}
], - "rating": {
- "value": 5,
- "total": 0
}, - "series": {
- "id": "string",
- "release_number": 0
}, - "ids": {
- "^[a-zA-Z0-9]+$": "string"
}, - "genres": [
- [
- "string"
]
], - "media_available_from": "string",
- "chapters": [
- {
- "title": "string",
- "description": "string",
- "offset": 0
}
], - "technical_protections": [
- "string"
]
}
]
}Replaces the ordering of the featured release collection with the provided list.
Authorization: Editorial admin only.
| X-Release-Cover-Sizes | integer header specifies sizes for Release cover basic objects. See Basic response object section for details. |
| X-Actor-Image-Sizes | string Header specifies sizes for Actor image objects. |
| X-Include | Array of strings Specify which additional sub-objects to include in a response. The value is a comma-separated list of object names. Valid names are:
|
Array of objects (id_object) |
{- "releases": [
- {
- "id": "string"
}
]
}{- "releases": [
- {
- "id": "string",
- "title": "string",
- "original_title": "string",
- "cover": {
- "release_id": 0,
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}, - "artist": {
- "id": "string",
- "name": "string",
- "url": "string"
}, - "actors": [
- {
- "id": "string",
- "name": "string",
- "sort_name": "string",
- "role": "string",
- "image": {
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}
}
], - "type": "album",
- "favourite": true,
- "url": "string",
- "copyright": "string",
- "release_date": "1997-07-16",
- "language": "string",
- "description": "string",
- "prices": [
- {
- "currency": "BDT",
- "price": 5.9
}
], - "notes": [
- {
- "id": "string",
- "summary": "string",
- "text": "string"
}
], - "reviews": [
- {
- "id": 0,
- "publication": "string",
- "publication_date": "string",
- "title": "string",
- "url": "string",
- "score": {
- "value": "string",
- "scale": {
- "min": 0,
- "max": 0
}, - "formatted": "3/6"
}
}
], - "rating": {
- "value": 5,
- "total": 0
}, - "series": {
- "id": "string",
- "release_number": 0
}, - "ids": {
- "^[a-zA-Z0-9]+$": "string"
}, - "genres": [
- [
- "string"
]
], - "media_available_from": "string",
- "chapters": [
- {
- "title": "string",
- "description": "string",
- "offset": 0
}
], - "technical_protections": [
- "string"
]
}
]
}Deletes the release group identified by group_id.
Authorization: Logged-in user required.
| group_id required | string |
| X-Change-Timestamp | string Time of change in UTC; defaults to the backend's current time. |
{- "error": "error_not_found",
- "error_description": "The requested resource was not found."
}Returns the release group identified by group_id.
In addition to numeric ids, a small set of predefined synthetic group aliases is supported; each represents a virtual group derived from the authenticated user's state:
purchased - lists purchased releases.borrowed - lists borrowed releases.finished - lists finished releases.played - lists recently played releases.wishlist - lists releases added to the wishlist.Authorization: Varies by path parameter — see the group_id description.
| group_id required | string Enum: "purchased" "borrowed" "finished" "played" "wishlist" "*" Either a numeric release group id or one of the predefined synthetic
aliases ( Authorization: Any valid bearer token for a numeric group id; synthetic aliases require a logged-in user (they operate on the caller's own state). |
| X-Release-Cover-Sizes | integer header specifies sizes for Release cover basic objects. See Basic response object section for details. |
| X-Release-Group-Image-Sizes | string |
| X-Actor-Image-Sizes | string Header specifies sizes for Actor image objects. |
| X-Include | Array of strings Specify which additional sub-objects to include in a response. The value is a comma-separated list of object names. Valid names are:
|
{- "group": {
- "id": "string",
- "name": "string",
- "description": "string",
- "image": {
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}, - "permission": "READ",
- "favourite": true,
- "releases": [
- {
- "id": "string",
- "title": "string",
- "original_title": "string",
- "cover": {
- "release_id": 0,
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}, - "artist": {
- "id": "string",
- "name": "string",
- "url": "string"
}, - "actors": [
- {
- "id": "string",
- "name": "string",
- "sort_name": "string",
- "role": "string",
- "image": {
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}
}
], - "type": "album",
- "favourite": true,
- "url": "string",
- "copyright": "string",
- "release_date": "1997-07-16",
- "language": "string",
- "description": "string",
- "prices": [
- {
- "currency": "BDT",
- "price": 5.9
}
], - "notes": [
- {
- "id": "string",
- "summary": "string",
- "text": "string"
}
], - "reviews": [
- {
- "id": 0,
- "publication": "string",
- "publication_date": "string",
- "title": "string",
- "url": "string",
- "score": {
- "value": "string",
- "scale": {
- "min": 0,
- "max": 0
}, - "formatted": "3/6"
}
}
], - "rating": {
- "value": 5,
- "total": 0
}, - "series": {
- "id": "string",
- "release_number": 0
}, - "ids": {
- "^[a-zA-Z0-9]+$": "string"
}, - "genres": [
- [
- "string"
]
], - "media_available_from": "string",
- "chapters": [
- {
- "title": "string",
- "description": "string",
- "offset": 0
}
], - "technical_protections": [
- "string"
]
}
]
}
}Partially updates a release group. All request body fields are optional, but at least one should be present.
When group_id is the predefined alias wishlist, the request body
should include the list of releases that should be present in the
wishlist (the list is replaced, not merged).
Authorization: Logged-in user required.
| group_id required | string Enum: "wishlist" "*" Either a numeric release group id or the predefined alias |
| X-Release-Group-Image-Sizes | string |
| X-Release-Cover-Sizes | integer header specifies sizes for Release cover basic objects. See Basic response object section for details. |
| X-Artist-Image-Sizes | string Header specifies sizes for Artist image basic object. |
| X-Base-Change | integer |
| X-Change-Timestamp | string |
| name | string |
| visible | boolean |
Array of objects (group_entry-2) May be empty. |
{- "name": "string",
- "visible": true,
- "releases": [
- {
- "id": "string"
}
]
}{- "group": {
- "id": "string",
- "name": "string",
- "description": "string",
- "image": {
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}, - "permission": "READ",
- "favourite": true,
- "releases": [
- {
- "id": "string",
- "title": "string",
- "original_title": "string",
- "cover": {
- "release_id": 0,
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}, - "artist": {
- "id": "string",
- "name": "string",
- "url": "string"
}, - "actors": [
- {
- "id": "string",
- "name": "string",
- "sort_name": "string",
- "role": "string",
- "image": {
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}
}
], - "type": "album",
- "favourite": true,
- "url": "string",
- "copyright": "string",
- "release_date": "1997-07-16",
- "language": "string",
- "description": "string",
- "prices": [
- {
- "currency": "BDT",
- "price": 5.9
}
], - "notes": [
- {
- "id": "string",
- "summary": "string",
- "text": "string"
}
], - "reviews": [
- {
- "id": 0,
- "publication": "string",
- "publication_date": "string",
- "title": "string",
- "url": "string",
- "score": {
- "value": "string",
- "scale": {
- "min": 0,
- "max": 0
}, - "formatted": "3/6"
}
}
], - "rating": {
- "value": 5,
- "total": 0
}, - "series": {
- "id": "string",
- "release_number": 0
}, - "ids": {
- "^[a-zA-Z0-9]+$": "string"
}, - "genres": [
- [
- "string"
]
], - "media_available_from": "string",
- "chapters": [
- {
- "title": "string",
- "description": "string",
- "offset": 0
}
], - "technical_protections": [
- "string"
]
}
]
}
}Removes release_id from the release group identified by group_id.
The group_id may be a numeric id or one of the supported synthetic
aliases (wishlist, purchased, etc.).
Authorization: Logged-in user required.
| group_id required | string |
| release_id required | integer |
[ ]Returns the releases that belong to one of the predefined synthetic
release groups for the authenticated user. Results are paginated via the
Range request header and Content-Range response header.
The response shape depends on the response_type query parameter:
response_type=id: items contain only the release id.Authorization: Logged-in user required.
| group_id required | string Enum: "purchased" "borrowed" "finished" "played" "wishlist" |
| release_ids | Array of strings Comma-separated list of release ids to restrict the response to,
limited to 1000 items. Supported with the |
| response_type | string If set to |
| X-Release-Cover-Sizes | integer header specifies sizes for Release cover basic objects. See Basic response object section for details. |
| X-Actor-Image-Sizes | string Header specifies sizes for Actor image objects. |
| X-Include | Array of strings Specify which additional sub-objects to include in a response. The value is a comma-separated list of object names. Valid names are:
|
| Range | string |
{- "releases": [
- {
- "id": "string",
- "title": "string",
- "original_title": "string",
- "cover": {
- "release_id": 0,
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}, - "artist": {
- "id": "string",
- "name": "string",
- "url": "string"
}, - "actors": [
- {
- "id": "string",
- "name": "string",
- "sort_name": "string",
- "role": "string",
- "image": {
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}
}
], - "type": "album",
- "favourite": true,
- "url": "string",
- "copyright": "string",
- "release_date": "1997-07-16",
- "language": "string",
- "description": "string",
- "prices": [
- {
- "currency": "BDT",
- "price": 5.9
}
], - "notes": [
- {
- "id": "string",
- "summary": "string",
- "text": "string"
}
], - "reviews": [
- {
- "id": 0,
- "publication": "string",
- "publication_date": "string",
- "title": "string",
- "url": "string",
- "score": {
- "value": "string",
- "scale": {
- "min": 0,
- "max": 0
}, - "formatted": "3/6"
}
}
], - "rating": {
- "value": 5,
- "total": 0
}, - "series": {
- "id": "string",
- "release_number": 0
}, - "ids": {
- "^[a-zA-Z0-9]+$": "string"
}, - "genres": [
- [
- "string"
]
], - "media_available_from": "string",
- "chapters": [
- {
- "title": "string",
- "description": "string",
- "offset": 0
}
], - "technical_protections": [
- "string"
]
}
]
}Adds a release to the release group identified by group_id. The
group_id may be a numeric id or one of the supported synthetic aliases
(wishlist, purchased, etc.).
Authorization: Logged-in user required.
| group_id required | string |
| release_id required | string Identifier of the release to add to the group. |
{- "release_id": "string"
}[ ]Returns all currently visible release groups, paginated via the Range
request header and Content-Range response header.
By default each group contains a list of release id references. If the
optional X-Include: group-releases header is sent the response embeds
full release base objects under releases instead.
Authorization: Any valid bearer token (app-only / visitor tokens are accepted).
| X-Release-Group-Image-Sizes | string |
| X-Release-Cover-Sizes | integer header specifies sizes for Release cover basic objects. See Basic response object section for details. |
| X-Actor-Image-Sizes | string Header specifies sizes for Actor image objects. |
| X-Include | Array of strings Specify which additional sub-objects to include in a response. The value is a comma-separated list of object names. Valid names are:
|
| Range | string |
{- "groups": [
- {
- "id": "string",
- "name": "string",
- "description": "string",
- "visible": true,
- "image": {
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}, - "permission": "READ",
- "favourite": true,
- "releases": [
- {
- "id": "string"
}
]
}
]
}Creates a new release group owned by the authenticated user. The initial set of releases may optionally be provided in the request body.
Authorization: Logged-in user required.
| X-Change-Timestamp | string Time of change in UTC; defaults to the backend's current time. |
| name required | string Human-readable name for the new group. |
| description | string Optional long-form description. |
Array of objects Optional initial set of releases to place in the group. |
{- "name": "string",
- "description": "string",
- "releases": [
- {
- "id": "string"
}
]
}{- "group": {
- "id": "string",
- "name": "string",
- "description": "string",
- "image": {
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}, - "permission": "READ",
- "favourite": true,
- "releases": [
- {
- "id": "string",
- "title": "string",
- "original_title": "string",
- "cover": {
- "release_id": 0,
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}, - "artist": {
- "id": "string",
- "name": "string",
- "url": "string"
}, - "actors": [
- {
- "id": "string",
- "name": "string",
- "sort_name": "string",
- "role": "string",
- "image": {
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}
}
], - "type": "album",
- "favourite": true,
- "url": "string",
- "copyright": "string",
- "release_date": "1997-07-16",
- "language": "string",
- "description": "string",
- "prices": [
- {
- "currency": "BDT",
- "price": 5.9
}
], - "notes": [
- {
- "id": "string",
- "summary": "string",
- "text": "string"
}
], - "reviews": [
- {
- "id": 0,
- "publication": "string",
- "publication_date": "string",
- "title": "string",
- "url": "string",
- "score": {
- "value": "string",
- "scale": {
- "min": 0,
- "max": 0
}, - "formatted": "3/6"
}
}
], - "rating": {
- "value": 5,
- "total": 0
}, - "series": {
- "id": "string",
- "release_number": 0
}, - "ids": {
- "^[a-zA-Z0-9]+$": "string"
}, - "genres": [
- [
- "string"
]
], - "media_available_from": "string",
- "chapters": [
- {
- "title": "string",
- "description": "string",
- "offset": 0
}
], - "technical_protections": [
- "string"
]
}
]
}
}Reorders the global list of release groups according to the order given in the request body.
Deprecated since v2.0; release-group ordering is now managed through the Layouts API rather than a dedicated reorder endpoint. Scheduled for removal TBD.
Authorization: Editorial admin only.
| X-Release-Group-Image-Sizes | string |
| X-Release-Cover-Sizes | integer header specifies sizes for Release cover basic objects. See Basic response object section for details. |
| X-Actor-Image-Sizes | string Header specifies sizes for Actor image objects. |
| X-Include | Array of strings Specify which additional sub-objects to include in a response. The value is a comma-separated list of object names. Valid names are:
|
Array of objects (Release Group Patch Request) Groups are reordered according to the natural order of this array. |
{- "groups": [
- {
- "id": "string"
}
]
}{- "groups": [
- {
- "id": "string",
- "name": "string",
- "description": "string",
- "visible": true,
- "image": {
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}, - "permission": "READ",
- "favourite": true,
- "releases": [
- {
- "id": "string"
}
]
}
]
}Returns the current, ordered list of featured release groups, paginated
via the Range request header and Content-Range response header.
If the optional X-Include: group-releases header is sent the response
embeds full release base objects under releases instead of id-only
references.
Authorization: Any valid bearer token (app-only / visitor tokens are accepted).
| X-Release-Group-Image-Sizes | string |
| X-Release-Cover-Sizes | integer header specifies sizes for Release cover basic objects. See Basic response object section for details. |
| X-Actor-Image-Sizes | string Header specifies sizes for Actor image objects. |
| X-Include | Array of strings Specify which additional sub-objects to include in a response. The value is a comma-separated list of object names. Valid names are:
|
| Range | string |
{- "groups": [
- {
- "id": "string",
- "name": "string",
- "description": "string",
- "visible": true,
- "image": {
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}, - "permission": "READ",
- "favourite": true,
- "releases": [
- {
- "id": "string"
}
]
}
]
}Replaces the ordered list of featured release groups. The order of the items in the request body determines the display order.
Authorization: Editorial admin only.
| X-Release-Group-Image-Sizes | string |
| X-Release-Cover-Sizes | integer header specifies sizes for Release cover basic objects. See Basic response object section for details. |
| X-Actor-Image-Sizes | string Header specifies sizes for Actor image objects. |
| X-Include | Array of strings Specify which additional sub-objects to include in a response. The value is a comma-separated list of object names. Valid names are:
|
Array of objects Ordered list of group id references to feature. |
{- "groups": [
- {
- "id": "string"
}
]
}{- "groups": [
- {
- "id": "string",
- "name": "string",
- "description": "string",
- "visible": true,
- "image": {
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}, - "permission": "READ",
- "favourite": true,
- "releases": [
- {
- "id": "string"
}
]
}
]
}Uploads a cover image for the release group identified by group_id.
The image must be sent as a multipart/form-data field named image.
Authorization: Editorial admin only.
| group_id required | string |
Multipart form body. The controller reads the uploaded file from
the image form field.
{ }Returns a paginated list of user ratings attached to the given release.
Authorization: Any valid bearer token (app-only / visitor tokens are accepted).
| release_id required | integer |
| Range | string |
{- "ratings": [
- {
- "id": "string",
- "value": 5,
- "note": "string",
- "entity_type": "release",
- "entity_id": "release_id, track_id or artist_id"
}
]
}Returns personalised recommendations for the authenticated user based on historical data (play logs, etc.).
Response is paginated via the Range / Content-Range headers.
Authorization: Logged-in user required.
| X-Release-Cover-Sizes | integer header specifies sizes for Release cover basic objects. See Basic response object section for details. |
| X-Artist-Image-Sizes | string Header specifies sizes for Artist image basic object. |
| X-Include | Array of strings Specify which additional sub-objects to include in a response. The value is a comma-separated list of object names. Valid names are:
|
| Range | string |
{- "releases": [
- {
- "id": "string",
- "title": "string",
- "original_title": "string",
- "cover": {
- "release_id": 0,
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}, - "artist": {
- "id": "string",
- "name": "string",
- "url": "string"
}, - "actors": [
- {
- "id": "string",
- "name": "string",
- "sort_name": "string",
- "role": "string",
- "image": {
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}
}
], - "type": "album",
- "favourite": true,
- "url": "string",
- "copyright": "string",
- "release_date": "1997-07-16",
- "language": "string",
- "description": "string",
- "prices": [
- {
- "currency": "BDT",
- "price": 5.9
}
], - "notes": [
- {
- "id": "string",
- "summary": "string",
- "text": "string"
}
], - "reviews": [
- {
- "id": 0,
- "publication": "string",
- "publication_date": "string",
- "title": "string",
- "url": "string",
- "score": {
- "value": "string",
- "scale": {
- "min": 0,
- "max": 0
}, - "formatted": "3/6"
}
}
], - "rating": {
- "value": 5,
- "total": 0
}, - "series": {
- "id": "string",
- "release_number": 0
}, - "ids": {
- "^[a-zA-Z0-9]+$": "string"
}, - "genres": [
- [
- "string"
]
], - "media_available_from": "string",
- "chapters": [
- {
- "title": "string",
- "description": "string",
- "offset": 0
}
], - "technical_protections": [
- "string"
]
}
]
}Returns a paginated list of bookmarks (entity_type track) across all tracks of the given release.
Authorization: Logged-in user required.
| release_id required | integer |
| Range | string |
{- "bookmarks": [
- {
- "id": "string",
- "entity_type": "track",
- "entity_id": "string",
- "added": "string",
- "note": "string",
- "position_type": "audio",
- "position": 0,
- "reader_position_selector": "epubcfi(/6/2!/0)",
- "reader_position_ratio": 1
}
]
}Returns a paginated list of playback progresses across the given release's tracks.
Deprecated since v2.0; use the Progresses API (GET /v2/progresses,
filtered by release/track) instead. Scheduled for removal TBD.
Authorization: Logged-in user required.
| release_id required | integer |
| Range | string |
{- "progresses": [
- {
- "id": "string",
- "entity_type": "track",
- "entity_id": "string",
- "changed": "string",
- "position_type": "audio",
- "stop_position": 0,
- "reader_position_selector": "epubcfi(/6/2!/0)",
- "reader_position_ratio": 1
}
]
}Looks up a release by its Universal Product Code.
Authorization: Any valid bearer token (app-only / visitor tokens are accepted).
| upc_code required | string Example: 0724382304258 |
| X-Release-Cover-Sizes | integer header specifies sizes for Release cover basic objects. See Basic response object section for details. |
| X-Actor-Image-Sizes | string Header specifies sizes for Actor image objects. |
{- "release": {
- "id": "string",
- "title": "string",
- "original_title": "string",
- "cover": {
- "release_id": 0,
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}, - "artist": {
- "id": "string",
- "name": "string",
- "url": "string"
}, - "actors": [
- {
- "id": "string",
- "name": "string",
- "sort_name": "string",
- "role": "string",
- "image": {
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}
}
], - "type": "album",
- "favourite": true,
- "url": "string",
- "copyright": "string",
- "release_date": "1997-07-16",
- "language": "string",
- "description": "string",
- "prices": [
- {
- "currency": "BDT",
- "price": 5.9
}
], - "notes": [
- {
- "id": "string",
- "summary": "string",
- "text": "string"
}
], - "reviews": [
- {
- "id": 0,
- "publication": "string",
- "publication_date": "string",
- "title": "string",
- "url": "string",
- "score": {
- "value": "string",
- "scale": {
- "min": 0,
- "max": 0
}, - "formatted": "3/6"
}
}
], - "rating": {
- "value": 5,
- "total": 0
}, - "series": {
- "id": "string",
- "release_number": 0
}, - "ids": {
- "^[a-zA-Z0-9]+$": "string"
}, - "genres": [
- [
- "string"
]
], - "media_available_from": "string",
- "chapters": [
- {
- "title": "string",
- "description": "string",
- "offset": 0
}
], - "technical_protections": [
- "string"
]
}
}Lists releases for the current catalog.
The endpoint behaves as a dispatcher based on query parameters:
query - full-text search over releases.series_id - releases belonging to a given series. Supports the Range: release_number=... header to filter by release number.rated_by - releases rated by a given user. Only honored when the value matches the caller's own user id.media_available_from - releases whose media becomes available on or after the given date (clamped to today). May be combined with licensor_id.banner_group_id - releases attached to a banner group.release_group_id - releases attached to a release group (by id or alias).When no recognised filter parameter is supplied, an empty paginated 206 response is returned.
Response is paginated via the Range / Content-Range headers.
Authorization: Any valid bearer token (app-only / visitor tokens are accepted).
| query | string Full-text search term. |
| series_id | string Filter by series id. |
| rated_by | string User id of the rater. Only returns results when it matches the authenticated user's id. |
| media_available_from | string <Y-m-d> Lower bound for |
| licensor_id | string Optional licensor id filter; only honored together with |
| banner_group_id | string Filter by releases attached to a banner group. |
| release_group_id | string Filter by releases attached to a release group (id or alias). |
| X-Release-Cover-Sizes | integer header specifies sizes for Release cover basic objects. See Basic response object section for details. |
| X-Actor-Image-Sizes | string Header specifies sizes for Actor image objects. |
| X-Include | Array of strings Specify which additional sub-objects to include in a response. The value is a comma-separated list of object names. Valid names are:
|
| Range | string Example: releases=20-39 Pagination range, e.g. |
{- "releases": [
- {
- "id": "string",
- "title": "string",
- "original_title": "string",
- "cover": {
- "release_id": 0,
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}, - "artist": {
- "id": "string",
- "name": "string",
- "url": "string"
}, - "actors": [
- {
- "id": "string",
- "name": "string",
- "sort_name": "string",
- "role": "string",
- "image": {
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}
}
], - "type": "album",
- "favourite": true,
- "url": "string",
- "copyright": "string",
- "release_date": "1997-07-16",
- "language": "string",
- "description": "string",
- "prices": [
- {
- "currency": "BDT",
- "price": 5.9
}
], - "notes": [
- {
- "id": "string",
- "summary": "string",
- "text": "string"
}
], - "reviews": [
- {
- "id": 0,
- "publication": "string",
- "publication_date": "string",
- "title": "string",
- "url": "string",
- "score": {
- "value": "string",
- "scale": {
- "min": 0,
- "max": 0
}, - "formatted": "3/6"
}
}
], - "rating": {
- "value": 5,
- "total": 0
}, - "series": {
- "id": "string",
- "release_number": 0
}, - "ids": {
- "^[a-zA-Z0-9]+$": "string"
}, - "genres": [
- [
- "string"
]
], - "media_available_from": "string",
- "chapters": [
- {
- "title": "string",
- "description": "string",
- "offset": 0
}
], - "technical_protections": [
- "string"
]
}
]
}Files a client-side report event (for example, playback telemetry or error reports) from the player.
Deprecated: This endpoint has been superseded by POST /v2/reports and
is retained only for backwards compatibility with older clients. New and
existing clients should migrate to the canonical endpoint, which shares the
same handler and accepts the same request payload.
The request body is forwarded as-is to the reports presenter; any JSON object is accepted. On success the endpoint returns an empty object.
Authorization: Any valid bearer token (app-only / visitor tokens are accepted).
Arbitrary report event payload. The structure is determined by the client and the reports presenter; any JSON object is accepted.
| property name* additional property | any |
{ }{- "error": "error_not_found",
- "error_description": "The requested resource was not found."
}Clients MUST collect each and every player/reader event and report them to POST /v2/reports. Clients must keep track of events in the offline mode and report them as soon as a connection establishes.
API
POST /v2/player/reports - still functional but deprecated in favour of more generic POST /v2/reportsPOST /v2/reports - accepts all types of reports listed belowReports
played-offlineMotitechplay.started - track-based report when player starts playing a new track in music servicesplay.ended - track-based report, mandatory for clients using /v2/streams/online and /v2/streams/offline endpoints to fetch a stream urlplay.progress - track-based playback progress tracking in audiobook services.play.error - track-based report when playing the current track failsNew event format
Important! These events require action to be set instead of event.
player.progress - track-/release-based report for tracking playback in audiobook servicesreader.progress - track-/release-based report for tracking reading in ebook services.reader.consumed - release-based report for when a release has been consumedrelease.finished - release-based report for a release being finishedVersioning
context field with data specific to a stream which clients get from the backend. Also we don't expect a shop field anymore.Example
Consider the following case:
The user plays a track from the beginning, 45 seconds later they seek to the 100th second, listens for 3 seconds, then presses "skip 30 seconds" twice, then listens for 40 more seconds, presses "pause", then "resume", listens for 15 more seconds and plays a different track.
The following reports should be sent:
play.started (start_position:0)
play.progress (start_position:0, stop_position:30)
play.progress (start_position:30, stop_position:45)
play.progress (start_position:163, stop_position:193)
play.progress (start_position:193, stop_position:203)
play.progress (start_position:203, stop_position:218)
play.ended (duration:103)\n\nplay.started (start_position:0)
Notice there is no report play.progress (start_position:100, stop_position:103) since user seeks to the 100th second, therefore we do not report progress until the track was played for 30 more seconds.
Here is another example illustrating the difference in report playback progress after seek vs after start/resume:
start 150 -> at 160 seek to 200 -> play for 20 more seconds -> seek to 250 -> play next track at 260:
play.started (start_position:150)
play.progress (start_position:150, stop_position:160)
play.progress (start_position:250, stop_position:260)
play.ended (duration:40)
vs.
start at 150 -> at 160 seek to 200 -> play for 35 more seconds -> seek to 250 -> play next track at 260:
play.started (start_position:150)
play.progress (start_position:150, stop_position:160)
play.progress (start_position:200, stop_position:230)
play.progress (start_position:230, stop_position:235)
play.progress (start_position:250, stop_position:260)
play.ended (duration:55)
Authorization: Any valid bearer token (app-only / visitor tokens are accepted).
| action required | string Value: "player.progress" |
| version required | integer Value: 3 |
| time required | integer event timestamp - seconds, unix epoch time |
| user_id required | string |
| device_id | string unique device-id set by the client |
| offline required | boolean |
| speed | number <float> 0.8 means |
| entity_type required | string Enum: "track" "release" |
| entity_id required | string corresponds to |
| start_position required | integer seconds since beginning of entity |
| stop_position required | integer seconds since beginning of entity |
| total_len | integer ex: length of release/track |
| sent_time required | integer timestamp when the event was sent from originator, unix epoch time |
| preview | boolean set if particular service requires reporting for previews |
| context | object arbitrary mapping, filled with an equivalent mapping provided by backend to clients along with the consumed content |
play.ended report
Report play.ended event.
Plays should be queued up for at most seven days (equal to the check-in time specified by the labels) when offline, to be sent when online again.
{- "event": "play.ended",
- "track_id": "123456",
- "time": 1305552557,
- "offline": false,
- "duration": 103,
- "stream_context": "release/1",
- "shop": "music-no"
}{- "error": "error_not_found",
- "error_description": "The requested resource was not found."
}Free-form per-user key/value metadata. Used to persist client-side preferences and integration state that does not warrant a dedicated schema.
Searches for series matching the given query string and returns a
paginated list of matches. When query is omitted or empty the
response is an empty array.
Use the standard Range request header to page through results; the
response uses 206 Partial Content with Accept-Ranges and
Content-Range headers.
The optional X-Series-Image-Sizes header controls which image size
variants are returned on embedded image objects.
Authorization: Any valid bearer token (app-only / visitor tokens are accepted).
| query | string |
| X-Series-Image-Sizes | string |
| Range | string |
{- "series": [
- {
- "id": "string",
- "name": "string",
- "description": "string",
- "image": {
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}
}
]
}Returns a single series resource identified by series_id.
The optional X-Series-Image-Sizes header controls which image size
variants are returned on the embedded image object.
Authorization: Any valid bearer token (app-only / visitor tokens are accepted).
| series_id required | string |
| X-Series-Image-Sizes | string |
{- "series": {
- "id": "string",
- "name": "string",
- "description": "string",
- "image": {
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}
}
}Updates the name and/or description of a series.
Deprecated since v2.0; series metadata is now managed through the editorial back-office rather than this API. No API replacement is planned. Scheduled for removal TBD.
Authorization: Editorial admin only.
| series_id required | string |
| X-Series-Image-Sizes | string |
| name | string New display name for the series. |
| description | string New description text for the series. |
{- "name": "string",
- "description": "string"
}{- "series": {
- "id": "string",
- "name": "string",
- "description": "string",
- "image": {
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}
}
}Uploads a new cover/portrait image for the series identified by
series_id. The image is sent as a multipart/form-data upload
under the image form field.
Authorization: Editorial admin only.
| series_id required | string |
| image | string <binary> JPEG image of the series. |
{ } Specify optional header X-Stream-Formats: */high, X-Stream-Formats: */normal, X-Stream-Formats: */low in order to adjust audio stream quality. Header value should go from streams object of TrackExtended object - see GET v2/tracks/:track_id for details.
Getting stream url normally requires user access token and user has be subscribed. However there is a way to get stream url based on different criteria. This is service specific.
Specify optional header X-Stream-Context: <entity_type>/<entity_id> in order to fetch full stream.
Return a signed URL to a short preview of a track or release. Previews are typically between 30 and 60 seconds long and are playable without a valid subscription.
By default the id path parameter is interpreted as a track ID. To request a release-level preview instead, set ns=release_id and pass the release ID as id.
Examples:
GET /v2/streams/previews/{track_id}GET /v2/streams/previews/{release_id}?ns=release_idAuthorization: Any valid bearer token (app-only / visitor tokens are accepted).
| id required | string Track ID when |
| ns | string Namespace of the |
{- "stream": {
- "id": "string",
- "url": "string",
- "duration": 0,
- "type": "string",
- "source": {
- "type": "string",
- "offset": 0
}, - "context": {
- "shop": "string"
}
}
}Return a signed URL that streams the full track for online playback. The URL is short-lived and pre-signed — clients should fetch it fresh for each playback session rather than caching it.
The X-Stream-Formats and X-Stream-Context headers can be used to influence the preferred audio format and to attach streaming context (for example the shop the stream is played in) to downstream play reports.
IMPORTANT: Clients MUST keep track of playback of streams obtained from this endpoint by sending play reports to the Player Reports API (POST /v2/player/reports). For a music service, use play.ended events; for an audiobook service, use play.progress events. Regardless of service type, set offline=false when the stream was played online (as fetched from this endpoint).
Authorization: Any valid bearer token (app-only / visitor tokens are accepted).
| track_id required | integer Numeric identifier of the track to stream. |
| X-Stream-Formats | Array of strings Header specifies stream quality. See Valid names are:
Header value should go from streams object of Track Extended object - see |
| X-Stream-Context | string Getting stream url normally requires user access token and user has to be subscribed. However there is a way to get stream url based on different criteria. This is service specific. Specify optional header |
{- "stream": {
- "id": "string",
- "url": "string",
- "duration": 0,
- "type": "string",
- "source": {
- "type": "string",
- "offset": 0
}, - "context": {
- "shop": "string"
}
}
}Return a signed URL that streams the full track, intended for download to the device for offline playback. The URL is short-lived and pre-signed.
Supports the X-Stream-Formats and X-Stream-Context headers (see the online stream endpoint for details).
IMPORTANT: Clients MUST keep track of playback of streams obtained from this endpoint by sending play reports to the Player Reports API (POST /v2/player/reports). For a music service, use play.ended events; for an audiobook service, use play.progress events. Regardless of service type, set offline=true when the stream was played offline (as fetched from this endpoint).
Authorization: Any valid bearer token (app-only / visitor tokens are accepted).
| track_id required | integer Numeric identifier of the track to stream. |
| X-Stream-Formats | Array of strings Header specifies stream quality. See Valid names are:
Header value should go from streams object of Track Extended object - see |
| X-Stream-Context | string Getting stream url normally requires user access token and user has to be subscribed. However there is a way to get stream url based on different criteria. This is service specific. Specify optional header |
{- "stream": {
- "id": "string",
- "url": "string",
- "duration": 0,
- "type": "string",
- "source": {
- "type": "string",
- "offset": 0
}, - "context": {
- "shop": "string"
}
}
}Return signed stream descriptors for every track in the given release. This lets a client fetch all playback URLs for an album or audiobook in a single call instead of requesting each track individually.
The X-Stream-Formats and X-Stream-Context headers supported by the single-track stream endpoints are honoured here as well.
Authorization: Any valid bearer token (app-only / visitor tokens are accepted).
| release_id required | integer Numeric identifier of the release whose tracks should be streamed. |
| X-Stream-Formats | Array of strings Header specifies stream quality. See Valid names are:
Header value should go from streams object of Track Extended object - see |
| X-Stream-Context | string Getting stream url normally requires user access token and user has to be subscribed. However there is a way to get stream url based on different criteria. This is service specific. Specify optional header |
{- "track": {
- "id": 0
}, - "streams": {
- "id": "string",
- "url": "string",
- "duration": 0,
- "type": "string",
- "source": {
- "type": "string",
- "offset": 0
}, - "context": {
- "shop": "string"
}
}
}Search the track catalogue for tracks whose metadata (title, subtitle, artist, actor, release, etc.) matches the supplied free-text query.
The response is a paginated list of extended track objects. Clients may request a specific window via the Range header (for example, tracks=20-39).
Authorization: Any valid bearer token (app-only / visitor tokens are accepted).
| query required | string Free-text search query. Must be non-empty. |
| Range | string Pagination range, e.g. |
| X-Release-Cover-Sizes | string Comma-separated list of requested release cover sizes. |
| X-Actor-Image-Sizes | string Comma-separated list of requested actor image sizes. |
{- "tracks": [
- {
- "id": "string",
- "title": "string",
- "subtitle": "string",
- "duration": 0,
- "duration_iso": "PT23M15.3S",
- "artist": {
- "id": "string",
- "name": "string",
- "url": "string"
}, - "actors": [
- {
- "id": "string",
- "name": "string",
- "sort_name": "string",
- "role": "string",
- "image": {
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}
}
], - "favourite": true,
- "url": "string",
- "release": {
- "id": "string",
- "title": "string",
- "original_title": "string",
- "cover": {
- "release_id": 0,
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}, - "artist": {
- "id": "string",
- "name": "string",
- "url": "string"
}, - "actors": [
- {
- "id": "string",
- "name": "string",
- "sort_name": "string",
- "role": "string",
- "image": {
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}
}
], - "type": "album",
- "favourite": true,
- "url": "string",
- "copyright": "string",
- "release_date": "1997-07-16",
- "language": "string",
- "description": "string",
- "prices": [
- {
- "currency": "BDT",
- "price": 5.9
}
], - "notes": [
- {
- "id": "string",
- "summary": "string",
- "text": "string"
}
], - "reviews": [
- {
- "id": 0,
- "publication": "string",
- "publication_date": "string",
- "title": "string",
- "url": "string",
- "score": {
- "value": "string",
- "scale": {
- "min": 0,
- "max": 0
}, - "formatted": "3/6"
}
}
], - "rating": {
- "value": 5,
- "total": 0
}, - "series": {
- "id": "string",
- "release_number": 0
}, - "ids": {
- "^[a-zA-Z0-9]+$": "string"
}, - "genres": [
- [
- "string"
]
], - "media_available_from": "string",
- "chapters": [
- {
- "title": "string",
- "description": "string",
- "offset": 0
}
], - "technical_protections": [
- "string"
]
}, - "prices": [
- {
- "currency": "BDT",
- "price": 5.9
}
], - "streams": [
- {
- "id": "string",
- "type": "string"
}
]
}
]
}Return the extended representation of a single track identified by track_id.
Optional expansions via the X-Include header:
track-prices — include pricing information in the response.track-streams — include stream descriptors in the response.Authorization: Any valid bearer token (app-only / visitor tokens are accepted).
| track_id required | integer Identifier of the track to retrieve. |
| X-Actor-Image-Sizes | string Comma-separated list of requested actor image sizes. |
| X-Release-Cover-Sizes | string Comma-separated list of requested release cover sizes. |
| X-Include | string Comma-separated list of optional expansions. Supported values: |
{- "track": {
- "id": "string",
- "title": "string",
- "subtitle": "string",
- "duration": 0,
- "duration_iso": "PT23M15.3S",
- "artist": {
- "id": "string",
- "name": "string",
- "url": "string"
}, - "actors": [
- {
- "id": "string",
- "name": "string",
- "sort_name": "string",
- "role": "string",
- "image": {
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}
}
], - "favourite": true,
- "url": "string",
- "release": {
- "id": "string",
- "title": "string",
- "original_title": "string",
- "cover": {
- "release_id": 0,
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}, - "artist": {
- "id": "string",
- "name": "string",
- "url": "string"
}, - "actors": [
- {
- "id": "string",
- "name": "string",
- "sort_name": "string",
- "role": "string",
- "image": {
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}
}
], - "type": "album",
- "favourite": true,
- "url": "string",
- "copyright": "string",
- "release_date": "1997-07-16",
- "language": "string",
- "description": "string",
- "prices": [
- {
- "currency": "BDT",
- "price": 5.9
}
], - "notes": [
- {
- "id": "string",
- "summary": "string",
- "text": "string"
}
], - "reviews": [
- {
- "id": 0,
- "publication": "string",
- "publication_date": "string",
- "title": "string",
- "url": "string",
- "score": {
- "value": "string",
- "scale": {
- "min": 0,
- "max": 0
}, - "formatted": "3/6"
}
}
], - "rating": {
- "value": 5,
- "total": 0
}, - "series": {
- "id": "string",
- "release_number": 0
}, - "ids": {
- "^[a-zA-Z0-9]+$": "string"
}, - "genres": [
- [
- "string"
]
], - "media_available_from": "string",
- "chapters": [
- {
- "title": "string",
- "description": "string",
- "offset": 0
}
], - "technical_protections": [
- "string"
]
}, - "prices": [
- {
- "currency": "BDT",
- "price": 5.9
}
], - "streams": [
- {
- "id": "string",
- "type": "string"
}
]
}
}Toggle the authenticated user's favourite flag on a track.
The operation is always treated as successful from the client's perspective. Custom headers accepted by the GET endpoint (such as X-Release-Cover-Sizes and X-Actor-Image-Sizes) may also be sent in order to control the shape of the returned track object.
Server merge semantics: a PATCH request is responsible for merging the object received from the client with the version stored on the server. The server resolves any conflicts, and the response contains the merged object. See the User Changes API for details.
Authorization: Logged-in user required.
| track_id required | integer Identifier of the track to patch. |
| X-Base-Change | integer Base change id. Defaults to |
| X-Change-Timestamp | string Time of change in UTC. Defaults to the current server time. |
| X-Actor-Image-Sizes | string Comma-separated list of requested actor image sizes. |
| X-Release-Cover-Sizes | string Comma-separated list of requested release cover sizes. |
| X-Include | string Comma-separated list of optional expansions. Supported values: |
Fields to patch. Only favourite is currently supported by the server and must be present.
| favourite required | boolean Whether the track should be marked as a favourite for the user. |
{- "favourite": true
}{- "track": {
- "id": "string",
- "title": "string",
- "subtitle": "string",
- "duration": 0,
- "duration_iso": "PT23M15.3S",
- "artist": {
- "id": "string",
- "name": "string",
- "url": "string"
}, - "actors": [
- {
- "id": "string",
- "name": "string",
- "sort_name": "string",
- "role": "string",
- "image": {
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}
}
], - "favourite": true,
- "url": "string",
- "release": {
- "id": "string",
- "title": "string",
- "original_title": "string",
- "cover": {
- "release_id": 0,
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}, - "artist": {
- "id": "string",
- "name": "string",
- "url": "string"
}, - "actors": [
- {
- "id": "string",
- "name": "string",
- "sort_name": "string",
- "role": "string",
- "image": {
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}
}
], - "type": "album",
- "favourite": true,
- "url": "string",
- "copyright": "string",
- "release_date": "1997-07-16",
- "language": "string",
- "description": "string",
- "prices": [
- {
- "currency": "BDT",
- "price": 5.9
}
], - "notes": [
- {
- "id": "string",
- "summary": "string",
- "text": "string"
}
], - "reviews": [
- {
- "id": 0,
- "publication": "string",
- "publication_date": "string",
- "title": "string",
- "url": "string",
- "score": {
- "value": "string",
- "scale": {
- "min": 0,
- "max": 0
}, - "formatted": "3/6"
}
}
], - "rating": {
- "value": 5,
- "total": 0
}, - "series": {
- "id": "string",
- "release_number": 0
}, - "ids": {
- "^[a-zA-Z0-9]+$": "string"
}, - "genres": [
- [
- "string"
]
], - "media_available_from": "string",
- "chapters": [
- {
- "title": "string",
- "description": "string",
- "offset": 0
}
], - "technical_protections": [
- "string"
]
}, - "prices": [
- {
- "currency": "BDT",
- "price": 5.9
}
], - "streams": [
- {
- "id": "string",
- "type": "string"
}
]
}
}Return a paginated list of the authenticated user's bookmarks on a single track. Clients may request a specific window via the Range header.
Authorization: Logged-in user required.
| track_id required | integer Identifier of the track whose bookmarks should be listed. |
| Range | string Pagination range, e.g. |
{- "bookmarks": [
- {
- "id": "string",
- "entity_type": "track",
- "entity_id": "string",
- "added": "string",
- "note": "string",
- "position_type": "audio",
- "position": 0,
- "reader_position_selector": "epubcfi(/6/2!/0)",
- "reader_position_ratio": 1
}
]
}Return the authenticated user's listening/reading progress associated with a single track.
Deprecated since v2.0; use the Progresses API (GET /v2/progresses and related endpoints) instead. Scheduled for removal TBD.
Authorization: Logged-in user required.
| track_id required | integer Identifier of the track to fetch progress for. |
{- "progress": {
- "id": "string",
- "entity_type": "track",
- "entity_id": "string",
- "changed": "string",
- "position_type": "audio",
- "stop_position": 0,
- "reader_position_selector": "epubcfi(/6/2!/0)",
- "reader_position_ratio": 1
}
}Endpoints under /v2/users cover account lifecycle (create, read, edit,
delete), social graph (friends), credentials, events, change-syncing for
offline-capable clients, and subscription management.
Throughout the examples below, replace api.{tenant}.beat.no with the
tenant host, <ACCESS_TOKEN> with a bearer token obtained from
POST /v2/oauth2/token, and
placeholders such as <USER_ID>, <TRACK_ID>, etc. with real values.
When the access token was issued via an end-user grant (
grant_type=password,grant_type=signed_msisdn, etc.), the:user_idreferenced below is that user's id. With a client-credentials token, the:user_idmust be supplied explicitly and the client must be a user admin client for cross-user operations.
All lookup variants of GET /v2/users accept different
query parameters.
# Lookup by msisdn
curl "https://api.{tenant}.beat.no/v2/users?msisdn=4742424242" \
-H "Authorization: Bearer <ACCESS_TOKEN>"
# Full-text search
curl "https://api.{tenant}.beat.no/v2/users?query=4242" \
-H "Authorization: Bearer <ACCESS_TOKEN>"
# List the authenticated account's profiles (account users)
curl "https://api.{tenant}.beat.no/v2/users?account_users=true" \
-H "Authorization: Bearer <ACCESS_TOKEN>"
# Lookup by external user id (partner integrations)
curl "https://api.{tenant}.beat.no/v2/users?external_user_id=<EXTID>&external_provider_id=<PROVIDER>" \
-H "Authorization: Bearer <ACCESS_TOKEN>"
POST /v2/users, GET /v2/users/{user_id},
PATCH /v2/users/{user_id}, and
DELETE /v2/users/{user_id}.
# Create a user (user admin clients can also set
# password+msisdn together and bypass email verification)
curl -X POST "https://api.{tenant}.beat.no/v2/users" \
-H "Authorization: Bearer <ACCESS_TOKEN>" \
-H "Content-Type: application/json" \
-d '{ "msisdn": "4742424242", "email": "ada@example.com" }'
# Fetch
curl "https://api.{tenant}.beat.no/v2/users/<USER_ID>" \
-H "Authorization: Bearer <ACCESS_TOKEN>"
# Edit
curl -X PATCH "https://api.{tenant}.beat.no/v2/users/<USER_ID>" \
-H "Authorization: Bearer <ACCESS_TOKEN>" \
-H "Content-Type: application/json" \
-d '{ "firstname": "Ada" }'
# Soft-delete
curl -X DELETE "https://api.{tenant}.beat.no/v2/users/<USER_ID>" \
-H "Authorization: Bearer <ACCESS_TOKEN>"
GET /v2/users/{user_id}/friends/registered returns the
subset of the user's contact list that maps to existing Beat accounts.
(GET /v2/users/{user_id}/friends for the full unfiltered list is on
the roadmap and not yet implemented.)
curl "https://api.{tenant}.beat.no/v2/users/<USER_ID>/friends/registered" \
-H "Authorization: Bearer <ACCESS_TOKEN>"
Add a credential to an existing user with
POST /v2/users/{user_id}/credentials, then complete the
verification with
POST /v2/users/{user_id}/credentials/verifications by
presenting the token that was delivered out-of-band (typically by email
or SMS).
# Initiate (e.g. add an email credential of type 6)
curl -X POST "https://api.{tenant}.beat.no/v2/users/<USER_ID>/credentials" \
-H "Authorization: Bearer <ACCESS_TOKEN>" \
-H "Content-Type: application/json" \
-d '{ "type": 6, "credential": "ada@example.com" }'
# Complete (token comes from the verification email/SMS)
curl -X POST "https://api.{tenant}.beat.no/v2/users/<USER_ID>/credentials/verifications" \
-H "Authorization: Bearer <ACCESS_TOKEN>" \
-H "Content-Type: application/json" \
-d '{ "type": 6, "token": "<VERIFICATION_TOKEN>" }'
For the no-user-context entry point that initiates verification before
the user account exists, see POST /v2/credentials.
GET /v2/users/{user_id}/events returns the user's personal
event feed (favourites, bookmarks, etc.).
curl "https://api.{tenant}.beat.no/v2/users/<USER_ID>/events" \
-H "Authorization: Bearer <ACCESS_TOKEN>" \
-H "Range: items=0-49"
The Changes API lets offline-capable clients sync personal changes made while disconnected. It covers favourites (tracks, releases, artists, users), release groups (bookshelves), bookmarks, and ratings.
Security: the change-sync flow is rejected for visitor tokens or tokens belonging to a different user — that would break per-user isolation.
Logout while offline: if the user logs out while offline with unsynced changes, the client should prompt them to reconnect and sync first; otherwise local changes will be lost.
The three endpoints involved:
HEAD /v2/users/{user_id}/changes — return the current
change_id for the user in the X-Change response header.POST /v2/batch — push a set of POST / PATCH /
DELETE subrequests; the response carries the merged versions of any
conflicting objects.GET /v2/users/{user_id}/changes — pull new changes since
the supplied base_change_id.If the client has no local base_change_id (i.e. has never synced),
fetch the current change id with a HEAD request and store it as the
local base_change_id:
curl -I "https://api.{tenant}.beat.no/v2/users/<USER_ID>/changes" \
-H "Authorization: Bearer <ACCESS_TOKEN>"
# Response includes: X-Change: <latest_change_id>
Compose all local changes into one or a few batch requests with each
subrequest tagged with the X-Base-Change and X-Change-Timestamp
headers (the latter must be in UTC if set):
curl -X POST "https://api.{tenant}.beat.no/v2/batch" \
-H "Authorization: Bearer <ACCESS_TOKEN>" \
-H "Content-Type: application/json" \
-d '{
"requests": [
{ "method": "POST", "url": "/v2/releases/groups", "body": { /* ... */ }, "headers": { "X-Base-Change": "123", "X-Change-Timestamp": "" } },
{ "method": "POST", "url": "/v2/releases/groups", "body": { /* ... */ }, "headers": { "X-Base-Change": "123", "X-Change-Timestamp": "" } },
{ "method": "PATCH", "url": "/v2/tracks/<TRACK_ID>", "body": { /* ... */ }, "headers": { "X-Base-Change": "123", "X-Change-Timestamp": "" } },
{ "method": "PATCH", "url": "/v2/releases/<RELEASE_ID>", "body": { /* ... */ }, "headers": { "X-Base-Change": "123", "X-Change-Timestamp": "" } },
{ "method": "DELETE", "url": "/v2/releases/groups/<ID>", "body": { /* ... */ }, "headers": { "X-Base-Change": "123", "X-Change-Timestamp": "" } }
]
}'
Server logic — for each PATCH / DELETE change in the request:
change_id for the given user, entry_type, and entry_id) and
capture latest_change_id and latest_change_timestamp.base_change_id == latest_change_id, accept the change.base_change_id < latest_change_id, resolve the conflict
between the change from the request and the one already on the
server:latest_change_timestamp.base_change_id > latest_change_id, client error — return
400 Bad Request.new_change_id.X-Change: new_change_id header
to the response.PATCH requests are responsible for merging the object received from
the client with the version stored on the server. Conflicts are
resolved server-side; the response from PATCH contains the merged
version of the object so the client can update its local copy.
Example of the rows added to user_changes:
intID, intUser_ID, intEntityType, intEntityID, intActionType, dteAdded, dteChanged
1, 5667, release-group, 132, PATCH, CURRENT_TIMESTAMP
2, 5667, release-group, 132, DELETE, CURRENT_TIMESTAMP
3, 123, track, 8, PATCH, CURRENT_TIMESTAMP
4, 5667, artist, 1, PATCH, CURRENT_TIMESTAMP
Batch response (count and order match the request):
{
"responses": [
{ "status": 201, "body": { "id": "123", "...": "merge result" }, "headers": { "X-Change": 1 } },
{ "status": 201, "body": { "id": "124", "...": "merge result" }, "headers": { "X-Change": 2 } },
{ "status": 200, "body": { "id": "8", "...": "merge result" }, "headers": { "X-Change": 81 } },
{ "status": 200, "body": { "id": "1", "...": "merge result" }, "headers": { "X-Change": 82 } },
{ "status": 404, "body": { "error_description": "Not found" } }
]
}
The client can ignore the response body but should parse X-Change
headers to advance its local base_change_id.
curl "https://api.{tenant}.beat.no/v2/users/<USER_ID>/changes?base_change_id=<BASE>" \
-H "Authorization: Bearer <ACCESS_TOKEN>" \
-H "Range: changes=0-99"
Response (206 Partial Content):
{
"changes": [
{ "id": 1, "method": "POST", "body": { "group": { /* Release group extended object */ } } },
{ "id": 2, "method": "POST", "body": { "group": { /* Release group extended object */ } } },
{ "id": 81, "method": "PATCH", "body": { "track": { /* Track extended object */ } } },
{ "id": 82, "method": "DELETE", "body": { "group": { "id": "123" } } }
]
}
Content-Range: changes 0-99/101 indicates more pages are available;
the client should continue paginating until the response stops returning
new entries. For PATCH and POST, update the local object with the
returned body. For DELETE, remove the local copy by id.
When the page is processed, set the local base_change_id to the max
change_id seen — the client is now caught up to that version.
A change object always has the shape:
{
"id": 1,
"method": "POST|PATCH|DELETE",
"body": {
"release": {
"id": "123"
}
}
}
The body key is one of track, release, artist, group, etc.,
depending on the change.
Inspect and manipulate the user's running subscriptions:
GET /v2/users/{user_id}/subscriptions — list all
subscriptions for the user.PATCH /v2/users/{user_id}/subscriptions/{subscription_id}
with { "state": 6 } to stop or { "state": 3 } to resume.DELETE /v2/users/{user_id}/subscriptions/{subscription_id}
to deactivate immediately.See the Subscription management walkthrough for end-to-end examples.
state |
Name | Lifecycle | Notes |
|---|---|---|---|
1 |
TRIALING |
live | Valid trial subscription. May transition to ACTIVE once payment is received when the trial ends. |
3 |
ACTIVE |
live | Normal, active subscription — not in trial, paid and up to date. |
5 |
RENEW_FAILURE |
problem | Most recent payment failed; subscription is in the dunning process. |
6 |
STOPPED |
live until expiry | Stopped by the user; will end at the end of the current period. |
7 |
DEACTIVATED |
end of life | Deactivated during a migrate. |
8 |
UNPAID |
end of life | Marked unpaid after the retry period expired and dunning's final action was "mark the subscription unpaid". |
9 |
INCOMPLETE |
live | Payment request issued; confirmation not yet received. |
Search for users. The shape of the returned user objects depends on the query parameters provided:
email or msisdn set, or account_users=true, an extended user object is returned (restricted to user admins or the authenticated account).external_provider_id and external_user_id set, a base user object is returned.Authorization: Varies by query parameter — see the parameter descriptions. The baseline is any valid bearer token.
string Search by email. Authorization: User admin client only. | |
| msisdn | string Search by msisdn. Authorization: User admin client only. |
| account_users | boolean List account users (profiles) for the authenticated account. Authorization: Logged-in user required. |
| external_user_id | string Search by external id. Must be specified together with |
| external_provider_id | string Search by external id. Must be specified together with |
| Range | string |
{- "users": [
- {
- "id": "string",
- "firstname": "string",
- "lastname": "string",
- "username": "string",
- "favourite": true,
- "favouritees_count": 0,
- "favourite_users_count": 0,
- "featureset": { }
}
]
}Create a new user. This endpoint covers several use cases:
email_token verification — the email is automatically marked as verified.password and msisdn together (normally disallowed).Authorization: Varies by request body — the three use cases above map to the three access levels. Normal signup accepts any valid bearer token (app-only / visitor tokens). Adding a profile-user requires a logged-in user. Admin user creation (setting password together with msisdn, or skipping email_token verification) requires a user admin client.
A random password will be generated for the account if none is provided.
| msisdn | string |
| firstname | string |
| lastname | string |
| username | string |
string | |
| password | string Password should not appear if |
| newsletter | boolean Default: false |
| intent | string Enum: "webshop" "subscription" Distinguishes the purpose of user creation within the same client. One of |
| profile_type | string Enum: "standard" "child" |
| email_token | string Email verification token. Requires |
| avatar_id | string |
| region | string The region that the user belongs to. |
{- "msisdn": "004712345678",
- "firstname": "string",
- "lastname": "string",
- "username": "string",
- "email": "email@beat.no",
- "password": "string",
- "newsletter": false,
- "intent": "webshop",
- "profile_type": "standard",
- "email_token": "string",
- "avatar_id": "string",
- "region": "NO"
}{- "user": {
- "id": "string",
- "firstname": "string",
- "lastname": "string",
- "username": "string",
- "favourite": true,
- "favouritees_count": 0,
- "favourite_users_count": 0,
- "featureset": { }
}
}Delete a profile-user from the authenticated account. Only applicable to profile-users; the master-user of the account cannot be deleted through this endpoint.
Authorization: Logged-in user required.
| user_id required | integer |
{ }Update a user.
Server logic: PATCH merges the object received from the client with the object stored on the server. The server resolves conflicts if any arise, and the response contains the merged version of the object. See the User Changes API for details.
Authorization: Logged-in user (patching the user they are authenticated as, or a profile-user they own), or user admin client (may patch any user).
| user_id required | integer |
| X-Base_Change | integer Base change id. Defaults to 0 server-side. |
| X-Change-Timestamp | string Time of change in UTC. Defaults to the current time on the backend. |
| X-User-Image-Sizes | string |
All parameters are optional, but at least one of them should be present.
| firstname | string |
| lastname | string |
string | |
| region | string |
| password | string |
| privacy_profile_private | boolean |
| favourite | boolean Follow or unfollow user. |
| newsletter | boolean Subscribe or unsubscribe to email newsletters. |
| payment_type | integer See the list of supported payment types on the User API (user object). |
| username | string |
| profile_type | string Enum: "standard" "child" |
{- "firstname": "string",
- "lastname": "string",
- "email": "string",
- "region": "string",
- "password": "string",
- "privacy_profile_private": true,
- "favourite": true,
- "newsletter": true,
- "payment_type": 0,
- "username": "string",
- "profile_type": "standard"
}{- "user": {
- "id": "string",
- "firstname": "string",
- "lastname": "string",
- "username": "string",
- "favourite": true,
- "favouritees_count": 0,
- "favourite_users_count": 0,
- "featureset": { }
}
}Get user account info (excluding any credentials such as password).
Authorization: Logged-in user, or user admin client.
| user_id required | integer |
| X-User-Image-Sizes | string |
{- "user": {
- "id": "string",
- "firstname": "string",
- "lastname": "string",
- "username": "string",
- "favourite": true,
- "favouritees_count": 0,
- "favourite_users_count": 0,
- "featureset": { }
}
}Perform a full GDPR deletion (right to be forgotten) for the specified user. This anonymizes all personal data, deactivates subscriptions, revokes tokens, and deletes associated user data (progress, favourites, bookmarks, campaign history, activations, partner data, user actions, changes, and external identifiers). The user record is retained with anonymized fields for referential integrity.
This endpoint is idempotent: calling it again for an already-deleted user returns 200 with a message instead of an error.
Authorization: User admin client only.
| user_id required | integer The internal Beat user ID of the user to delete. Use |
{- "message": "User was already deleted previously."
}Attaches a credit card (represented by a Stripe JS SDK token) to the
user's Stripe account. On success the user's default payment type is
changed to Stripe — see payment_type on the User entity in the User
API.
Authorization: Logged-in user required.
| user_id required | integer |
| token required | string Credit card token issued by the Stripe JS SDK. |
{- "token": "string"
}{ }Fetches the user's personal change feed.
GET /v2/users/:user_id/changes returns
all personal changes.GET /v2/users/:user_id/changes?base_change_id=:base_change_id
returns changes after the client's local base_change_id (the change_id
from the previous synchronisation, incremented by 1).Authorization: Logged-in user required.
| user_id required | integer |
| base_change_id | string |
| Range | string e.g. |
| X-Release-Cover-Sizes | integer header specifies sizes for Release cover basic objects. See Basic response object section for details. |
| X-Artist-Image-Sizes | string Header specifies sizes for Artist image basic object. |
| X-Actor-Image-Sizes | string Header specifies sizes for Actor image objects. |
| X-User-Image-Sizes | string |
| X-Release-Group-Image-Sizes | string |
| X-Include | Array of strings Specify which additional sub-objects to include in a response. The value is a comma-separated list of object names. Valid names are:
|
{- "changes": [
- {
- "id": 1,
- "method": "POST"
}, - {
- "id": 2,
- "method": "PATCH"
}, - {
- "id": 81,
- "method": "POST"
}, - {
- "id": 82,
- "method": "PATCH"
}
]
}Returns the latest change_id of personal changes, typically used right
after the user logs in.
Because the API returns the latest state of personal collections, the
client needs to know the latest change_id. With it, the client can skip
fetching the full history of user changes and jump straight to the latest
state, which significantly speeds up initial synchronisation when logging
in to an existing account.
When the response is received, the client should set its local
base_change_id to the change_id from the response (meaning the client
has been upgraded up to that change_id version).
Authorization: Logged-in user required.
| user_id required | integer |
{- "error": "validation_error",
- "error_description": "The request body failed validation."
}Lists coupons owned by the user. Supports regular pagination via the
Range header.
Authorization: Logged-in user required.
| user_id required | integer |
| type required | string Type of coupons to list. Currently only |
| X-Coupon-Offer-Image-Sizes | string |
| Range | string |
{- "coupons": [
- {
- "id": "string",
- "code": "string",
- "interval": 6,
- "interval_unit": "MONTH",
- "valid": true,
- "used": true,
- "created": "string",
- "product_id": "string",
- "payment_state": 0,
- "payment_updated": "string",
- "balance_unit": "string",
- "balance_amount": 0,
- "renewable": true,
- "offer_id": "string",
- "name": "3 month membership",
- "image": {
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}
}
]
}Returns the paginated list of coupons that the authenticated user has redeemed. Intended for the account-history / receipts view.
Use the Range: items=<start>-<end> header to request a page; responses
use 206 Partial Content with a Content-Range header indicating the
returned slice.
Authorization: Logged-in user required.
The target user_id in the path must match the authenticated user.
| user_id required | integer Identifier of the user whose redemptions to list. |
| Range | string Range header in the form |
{- "redemptions": [
- {
- "id": "string",
- "code": "string",
- "interval": 6,
- "interval_unit": "MONTH",
- "valid": true,
- "used": true,
- "created": "string",
- "product_id": "string",
- "payment_state": 0,
- "payment_updated": "string",
- "balance_unit": "string",
- "balance_amount": 0,
- "renewable": true,
- "offer_id": "string",
- "name": "3 month membership",
- "image": {
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}
}
]
}Redeems a coupon for the target account. Depending on the coupon, this either extends an existing subscription or activates a brand-new one.
To look up user_id from an identifier, use GET /v2/user?msisdn=:msisdn.
Authorization: Logged-in user required.
The target user_id in the path must match the authenticated user.
| user_id required | string |
| coupon | string |
{- "coupon": "string"
}{- "error": "error_not_found",
- "error_description": "The requested resource was not found."
}Bind a credential to the account, or accept it for verification.
Binds a new type of credential to the user account. If the credential requires verification, this initiates the verification process by sending a verification email or SMS.
Authorization: Logged-in user required.
| user_id required | integer |
| type required | integer Enum: 5 6 7 8 9 10 Credential type. One of:
|
| credential required | string |
{- "type": 5,
- "credential": "string"
}{- "error": "error_not_found",
- "error_description": "The requested resource was not found."
}Submit a credential (for example, an email address) and initiate the associated verification flow without attaching it to a specific user account. The server stores the pending credential and dispatches a verification token through the appropriate channel (e.g. an e-mail containing a verification link or code).
This endpoint is used in onboarding flows where the credential must be verified before a user account is fully activated or linked. The subsequent verification step is completed via POST /v2/users/{user_id}/credentials/verifications.
The credential type must be one that supports a verification process; types without a configured verification method are rejected with 400 Bad Request.
Authorization: Any valid bearer token (app-only / visitor tokens are accepted).
| type required | integer Enum: 6 8 Numeric credential type identifier (see
Must correspond to a type that has a verification method configured on the server. Unsupported types are rejected with |
| credential required | string The credential value to verify. For e-mail credential types, this is the e-mail address that the verification token will be sent to. |
{- "type": 8,
- "credential": "user@example.com"
}{ }Complete a credential verification by submitting the one-time token delivered via email or SMS.
Authorization: Any valid bearer token (app-only / visitor tokens are accepted).
| user_id required | integer |
| token | string |
| type | integer Enum: 5 6 7 8 9 10 Credential type. One of:
|
{- "token": "string",
- "type": 5
}{ }Lists events for the given user. Events are generated by the backend; at
present they come from PATCH /v2/users/:id and PATCH /v2/artists/:id
when the favourite flag changes.
Authorization: Logged-in user required.
| user_id required | integer |
| Range | string |
| X-Artist-Image-Sizes | string Header specifies sizes for Artist image basic object. |
| X-Release-Cover-Sizes | integer header specifies sizes for Release cover basic objects. See Basic response object section for details. |
| X-Actor-Image-Sizes | string Header specifies sizes for Actor image objects. |
{- "events": [
- {
- "id": "string",
- "title": "Album of the week",
- "created": "string",
- "source_type": "user",
- "source": {
- "id": "string",
- "firstname": "string",
- "lastname": "string",
- "username": "string",
- "favourite": true,
- "favouritees_count": 0,
- "favourite_users_count": 0,
- "featureset": { }
}, - "action_id": "string",
- "target_type": "user",
- "target": {
- "id": "string",
- "firstname": "string",
- "lastname": "string",
- "username": "string",
- "favourite": true,
- "favouritees_count": 0,
- "favourite_users_count": 0,
- "featureset": { }
}
}
]
}Lists the users who have favourited the given user.
Authorization: Logged-in user required.
| user_id required | integer |
| Range | string |
{- "users": [
- {
- "id": "string",
- "firstname": "string",
- "lastname": "string",
- "username": "string",
- "favourite": true,
- "favouritees_count": 0,
- "favourite_users_count": 0,
- "featureset": { }
}
]
}Lists the artists the user has favourited.
Authorization: Logged-in user required.
| user_id required | integer |
| X-Artist-Image-Sizes | string Header specifies sizes for Artist image basic object. |
| Range | string |
{- "artists": [
- {
- "id": "string",
- "name": "string",
- "url": "string",
- "image": {
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}, - "favourite": true
}
]
}Lists the releases the user has favourited.
Authorization: Logged-in user required.
| user_id required | integer |
| types | string Comma-separated list of release types. May include shortened
See the Release API for details. |
| Range | string |
| X-Release-Cover-Sizes | integer header specifies sizes for Release cover basic objects. See Basic response object section for details. |
| X-Actor-Image-Sizes | string Header specifies sizes for Actor image objects. |
| X-Include | Array of strings Specify which additional sub-objects to include in a response. The value is a comma-separated list of object names. Valid names are:
|
{- "releases": [
- {
- "id": "string",
- "title": "string",
- "original_title": "string",
- "cover": {
- "release_id": 0,
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}, - "artist": {
- "id": "string",
- "name": "string",
- "url": "string"
}, - "actors": [
- {
- "id": "string",
- "name": "string",
- "sort_name": "string",
- "role": "string",
- "image": {
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}
}
], - "type": "album",
- "favourite": true,
- "url": "string",
- "copyright": "string",
- "release_date": "1997-07-16",
- "language": "string",
- "description": "string",
- "prices": [
- {
- "currency": "BDT",
- "price": 5.9
}
], - "notes": [
- {
- "id": "string",
- "summary": "string",
- "text": "string"
}
], - "reviews": [
- {
- "id": 0,
- "publication": "string",
- "publication_date": "string",
- "title": "string",
- "url": "string",
- "score": {
- "value": "string",
- "scale": {
- "min": 0,
- "max": 0
}, - "formatted": "3/6"
}
}
], - "rating": {
- "value": 5,
- "total": 0
}, - "series": {
- "id": "string",
- "release_number": 0
}, - "ids": {
- "^[a-zA-Z0-9]+$": "string"
}, - "genres": [
- [
- "string"
]
], - "media_available_from": "string",
- "chapters": [
- {
- "title": "string",
- "description": "string",
- "offset": 0
}
], - "technical_protections": [
- "string"
]
}
]
}Lists the tracks the user has favourited.
Authorization: Logged-in user required.
| user_id required | integer |
| Range | string |
| X-Actor-Image-Sizes | string Header specifies sizes for Actor image objects. |
{- "tracks": [
- {
- "id": "string",
- "title": "string",
- "subtitle": "string",
- "duration": 0,
- "duration_iso": "PT23M15.3S",
- "artist": {
- "id": "string",
- "name": "string",
- "url": "string"
}, - "actors": [
- {
- "id": "string",
- "name": "string",
- "sort_name": "string",
- "role": "string",
- "image": {
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}
}
], - "favourite": true,
- "url": "string",
- "release": {
- "id": "string",
- "title": "string",
- "original_title": "string",
- "cover": {
- "release_id": 0,
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}, - "artist": {
- "id": "string",
- "name": "string",
- "url": "string"
}, - "actors": [
- {
- "id": "string",
- "name": "string",
- "sort_name": "string",
- "role": "string",
- "image": {
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}
}
], - "type": "album",
- "favourite": true,
- "url": "string",
- "copyright": "string",
- "release_date": "1997-07-16",
- "language": "string",
- "description": "string",
- "prices": [
- {
- "currency": "BDT",
- "price": 5.9
}
], - "notes": [
- {
- "id": "string",
- "summary": "string",
- "text": "string"
}
], - "reviews": [
- {
- "id": 0,
- "publication": "string",
- "publication_date": "string",
- "title": "string",
- "url": "string",
- "score": {
- "value": "string",
- "scale": {
- "min": 0,
- "max": 0
}, - "formatted": "3/6"
}
}
], - "rating": {
- "value": 5,
- "total": 0
}, - "series": {
- "id": "string",
- "release_number": 0
}, - "ids": {
- "^[a-zA-Z0-9]+$": "string"
}, - "genres": [
- [
- "string"
]
], - "media_available_from": "string",
- "chapters": [
- {
- "title": "string",
- "description": "string",
- "offset": 0
}
], - "technical_protections": [
- "string"
]
}, - "prices": [
- {
- "currency": "BDT",
- "price": 5.9
}
], - "streams": [
- {
- "id": "string",
- "type": "string"
}
]
}
]
}Lists the users that the given user has favourited.
Authorization: Logged-in user required.
| user_id required | integer |
| Range | string |
{- "users": [
- {
- "id": "string",
- "firstname": "string",
- "lastname": "string",
- "username": "string",
- "favourite": true,
- "favouritees_count": 0,
- "favourite_users_count": 0,
- "featureset": { }
}
]
}Returns the free-form key/value metadata bag stored for the target user. Metadata is used to persist client-side preferences and integration state that does not warrant a dedicated schema.
Authorization: Logged-in user (only for their own metadata, i.e.
{user_id} matches the caller), or user admin client (for any user).
Other callers receive 403 Forbidden.
| user_id required | integer Identifier of the target user. |
{- "property1": "string",
- "property2": "string"
}Merges the supplied key/value pairs into the target user's metadata bag. On key collision, the supplied value overwrites the stored value. Keys not present in the request body are left unchanged (this endpoint does not replace the entire bag — use DELETE to remove keys).
Limits enforced server-side:
409 Conflict).Authorization: User admin client only. Other callers, including
the target user themselves, receive 400 Bad Request with
"Insufficient permissions".
| user_id required | integer Identifier of the target user. |
Key/value pairs to merge into the user's metadata bag.
| property name* additional property | string <= 500 characters |
{- "device_id": "abc-123",
- "app_variant": "premium"
}{ }Removes the metadata entry identified by key from the target user's
metadata bag. Other entries are left untouched.
Authorization: User admin client only. Other callers, including
the target user themselves, receive 400 Bad Request with
"Insufficient permissions".
| user_id required | integer Identifier of the target user. |
| key required | string <= 40 characters Metadata key to delete. |
{ }Activate a subscription based on the given product id (upgrade or downgrade logic).
Authorization: Logged-in user required.
| user_id required | integer |
| product_id required | string |
| renewable | boolean Whether the new subscription should renew. Defaults to |
| utm_campaign | string UTM campaign name. May adjust the subscription trial period if specified. |
| confirmed | boolean Defaults to |
| metadata | object <json> A JSON structure for associating information with the subscription. |
{- "product_id": "string",
- "renewable": true,
- "utm_campaign": "string",
- "confirmed": true,
- "metadata": { }
}{ }Deprecated alias for GET /v2/users/{user_id}/favourites/releases. Use
the newer endpoint in new integrations.
Known clients still using this route:
v2.3.5.Authorization: Logged-in user required.
| user_id required | integer |
| Range | string |
| X-Release-Cover-Sizes | integer header specifies sizes for Release cover basic objects. See Basic response object section for details. |
| X-Actor-Image-Sizes | string Header specifies sizes for Actor image objects. |
| X-Include | Array of strings Specify which additional sub-objects to include in a response. The value is a comma-separated list of object names. Valid names are:
|
{- "releases": [
- {
- "id": "string",
- "title": "string",
- "original_title": "string",
- "cover": {
- "release_id": 0,
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}, - "artist": {
- "id": "string",
- "name": "string",
- "url": "string"
}, - "actors": [
- {
- "id": "string",
- "name": "string",
- "sort_name": "string",
- "role": "string",
- "image": {
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}
}
], - "type": "album",
- "favourite": true,
- "url": "string",
- "copyright": "string",
- "release_date": "1997-07-16",
- "language": "string",
- "description": "string",
- "prices": [
- {
- "currency": "BDT",
- "price": 5.9
}
], - "notes": [
- {
- "id": "string",
- "summary": "string",
- "text": "string"
}
], - "reviews": [
- {
- "id": 0,
- "publication": "string",
- "publication_date": "string",
- "title": "string",
- "url": "string",
- "score": {
- "value": "string",
- "scale": {
- "min": 0,
- "max": 0
}, - "formatted": "3/6"
}
}
], - "rating": {
- "value": 5,
- "total": 0
}, - "series": {
- "id": "string",
- "release_number": 0
}, - "ids": {
- "^[a-zA-Z0-9]+$": "string"
}, - "genres": [
- [
- "string"
]
], - "media_available_from": "string",
- "chapters": [
- {
- "title": "string",
- "description": "string",
- "offset": 0
}
], - "technical_protections": [
- "string"
]
}
]
}Returns a tracking identifier that can be used for the user for analytics or advertising purposes.
Authorization: Logged-in user required.
| user_id required | integer |
{- "tracking": {
- "identifier": "string"
}
}Lists subscriptions for the given user.
By default only running subscriptions are returned. Pass state to
filter by a specific state, or state=all to include every subscription
regardless of state.
Authorization: Logged-in user required.
| user_id required | integer |
| state | string If specified, returns subscriptions filtered by state. Use
|
| Range | string |
{- "subscriptions": [
- {
- "id": "string",
- "product_id": "string",
- "surface_id": "string",
- "biller_id": "string",
- "start_date": "2019-08-24T14:15:22Z",
- "expiry_date": "2019-08-24T14:15:22Z",
- "next_billing_date": "string",
- "state": 0,
- "metadata": { },
- "offline_media_expiry_date": "2019-08-24T14:15:22Z",
- "partner": {
- "id": "string",
- "title": "string"
}, - "children": [ ]
}
]
}Stop or resume a subscription. Only the subscription's owner may call this endpoint.
Authorization: Logged-in user required.
| user_id required | integer |
| subscription_id required | string |
| state required | integer Target state. Only two transitions are allowed:
All other values are rejected. |
| comment | string Optional feedback when the user stops the subscription. |
{- "state": 0,
- "comment": "string"
}{- "subscription": {
- "id": "string",
- "product_id": "string",
- "surface_id": "string",
- "biller_id": "string",
- "start_date": "2019-08-24T14:15:22Z",
- "expiry_date": "2019-08-24T14:15:22Z",
- "next_billing_date": "string",
- "state": 0,
- "metadata": { },
- "offline_media_expiry_date": "2019-08-24T14:15:22Z"
}
}Terminates the given subscription. When called by the subscription's owner the subscription is treated as self-terminated; when called by a user admin client the subscription is terminated administratively.
Authorization: Logged-in user required.
| user_id required | integer |
| subscription_id required | string |
{- "error": "error_not_found",
- "error_description": "The requested resource was not found."
}A user can have balances in multiple currencies. This lists the user's current balances by currency.
For most services, only a single currency will be returned. There are some special currency codes:
XCR means "credits".XCS means "seconds".Not receiving a balance in a currency is equivalent to receiving a zero balance in that currency.
Authorization: Logged-in user required.
| user_id | integer |
| Range | string |
{- "balances": [
- {
- "amount": 0,
- "unit": "string"
}
]
}Deprecated alias for POST /v2/charges. New integrations should use the
generic endpoint directly; this route is preserved only for backwards
compatibility and dispatches to the same controller.
The request body and response shapes are identical to
POST /v2/charges; see that spec for the full property-level
documentation.
Authorization: Varies by request body — see the reason property.
Any valid bearer token is the baseline; reason=external_charge
additionally requires a bearer token with the external-charge scope.
| user_id required | integer |
Same shape as the request body of POST /v2/charges. The user_id in
the path takes precedence over any user_id in the body.
| reason required | string Enum: "offlining" "coupon" "purchase" "campaign" "external_charge" "vipps_initial_charge" "vipps_renew" |
| entity_type required | string Enum: "track" "release" "coupon" "campaign" "balance" |
| entity_id | string |
| payment_type | integer |
| source | string |
string | |
| recipient_name | string |
| message | string |
| amount | integer |
| unit | string Enum: "XCR" "EUR" |
{- "reason": "offlining",
- "entity_type": "track",
- "entity_id": "string",
- "payment_type": 0,
- "source": "string",
- "email": "string",
- "recipient_name": "string",
- "message": "string",
- "amount": 0,
- "unit": "XCR"
}{- "id": "string"
}Lists the user's personal release groups (bookshelves).
If the optional X-Include: group-releases header is set, each group's
releases are returned as full Release base objects instead of ID-only
references.
Authorization: Logged-in user required.
| user_id required | integer |
| Range | string |
| X-Release-Group-Image-Sizes | string |
| X-Release-Cover-Sizes | integer header specifies sizes for Release cover basic objects. See Basic response object section for details. |
| X-Actor-Image-Sizes | string Header specifies sizes for Actor image objects. |
| X-Include | Array of strings Specify which additional sub-objects to include in a response. The value is a comma-separated list of object names. Valid names are:
|
{- "groups": [
- {
- "id": "string",
- "name": "string",
- "description": "string",
- "visible": true,
- "image": {
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}, - "permission": "READ",
- "favourite": true,
- "releases": [
- {
- "id": "string"
}
]
}
]
}Returns one of the user's synthetic release groups — an auto-curated
bookshelf such as purchased, borrowed, finished, played, or
wishlist.
Authorization: Logged-in user (only as the target user / resource owner), or user admin client.
| user_id required | integer |
| synthetic required | string Enum: "purchased" "borrowed" "finished" "played" "wishlist" |
| X-Release-Group-Image-Sizes | string |
| X-Release-Cover-Sizes | integer header specifies sizes for Release cover basic objects. See Basic response object section for details. |
| X-Actor-Image-Sizes | string Header specifies sizes for Actor image objects. |
| X-Include | Array of strings Specify which additional sub-objects to include in a response. The value is a comma-separated list of object names. Valid names are:
|
{- "group": {
- "id": "string",
- "name": "string",
- "description": "string",
- "image": {
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}, - "permission": "READ",
- "favourite": true,
- "releases": [
- {
- "id": "string",
- "title": "string",
- "original_title": "string",
- "cover": {
- "release_id": 0,
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}, - "artist": {
- "id": "string",
- "name": "string",
- "url": "string"
}, - "actors": [
- {
- "id": "string",
- "name": "string",
- "sort_name": "string",
- "role": "string",
- "image": {
- "w50": "string",
- "h200": "string",
- "w200": "string",
- "w800": "string"
}
}
], - "type": "album",
- "favourite": true,
- "url": "string",
- "copyright": "string",
- "release_date": "1997-07-16",
- "language": "string",
- "description": "string",
- "prices": [
- {
- "currency": "BDT",
- "price": 5.9
}
], - "notes": [
- {
- "id": "string",
- "summary": "string",
- "text": "string"
}
], - "reviews": [
- {
- "id": 0,
- "publication": "string",
- "publication_date": "string",
- "title": "string",
- "url": "string",
- "score": {
- "value": "string",
- "scale": {
- "min": 0,
- "max": 0
}, - "formatted": "3/6"
}
}
], - "rating": {
- "value": 5,
- "total": 0
}, - "series": {
- "id": "string",
- "release_number": 0
}, - "ids": {
- "^[a-zA-Z0-9]+$": "string"
}, - "genres": [
- [
- "string"
]
], - "media_available_from": "string",
- "chapters": [
- {
- "title": "string",
- "description": "string",
- "offset": 0
}
], - "technical_protections": [
- "string"
]
}
]
}
}Adds a release to one of the user's release groups (bookshelves).
Authorization: Logged-in user (only as the target user / resource owner), or user admin client.
| user_id required | integer |
| group_id required | string |
| X-Change-Timestamp | string |
Identifier of the release to add to the group.
| id required | string Identifier of the release to add. |
{- "id": "string"
}{- "id": "string"
}Marks a pending partner activation as confirmed for the authenticated user. This is typically called after the user has successfully logged in (or set a password) on the confirmation landing page, in order to activate the associated subscription.
If the activation has already been confirmed previously, the endpoint
responds with 208 Already Reported instead of an error.
Authorization: Logged-in user required.
| activation_id required | integer Identifier of the activation to confirm. |
| state required | string Value: "CONFIRMED" Target state. Must be |
{- "state": "CONFIRMED"
}{ }Looks up a partner activation by its one-time confirmation_code (typically
embedded in a confirmation link sent to the user by email). The response
describes which follow-up step the client should render next: a login form
for an existing user, or a password-set form for a newly created user.
This endpoint is intended to be called from the confirmation landing page using a visitor token obtained via the standard OAuth2 flow.
Authorization: Any valid bearer token (app-only / visitor tokens are accepted).
| confirmation_code required | string One-time confirmation code from the activation link. |
{- "activations": [
- {
- "id": "string",
- "user": {
- "email": "string",
- "msisdn": "string",
- "firstname": "string",
- "lastname": "string",
- "new_password_required": true
}, - "product": {
- "id": "string",
- "name": "string",
- "description": "string"
}, - "partner": {
- "id": "string",
- "title": "string",
- "confirmation_url": "string"
}, - "state": "UNCONFIRMED"
}
]
}Endpoints under /v2/partnerusers/* let a partner create and manage
users (and their subscriptions) on the partner's behalf — without
requiring an end-user OAuth flow. Typical use cases: bulk onboarding
from a partner system, account creation as part of a co-branded sign-up,
and stopping subscriptions when a partner relationship ends.
Partner-users endpoints use a separate authentication scheme from the
rest of the API: a partner-specific client id / secret pair sent as
HTTP headers (rather than an OAuth bearer token). The schemes are
defined in openapi.yaml as partnerClientId and partnerClientSecret.
A partner is provisioned with one or more clients; use the
client_id and client_secret for each request:
X-Auth-Client-Id: <client_id>
X-Auth-Client-Secret: <client_secret>
Requests without valid credentials get 401 Unauthorized with an empty
body.
POST /v2/partnerusers/activations — create or
look up a user, associate them with the partner, and add a subscription.DELETE /v2/partnerusers/activations/{activation_id}
— end the subscription associated with the activation.Provide a partner-local external_id, a product to subscribe the
user to, and (optionally) user details used when creating a new user
or matching an existing one by email/msisdn.
curl -X POST "https://api.{tenant}.beat.no/v2/partnerusers/activations" \
-H "X-Auth-Client-Id: <CLIENT_ID>" \
-H "X-Auth-Client-Secret: <CLIENT_SECRET>" \
-H "Content-Type: application/json" \
-d '{
"partneruser": {
"external_id": "PARTNER-USR-123"
},
"user": {
"email": "ada@example.com",
"firstname": "Ada",
"lastname": "Lovelace"
},
"product": {
"id": "13"
}
}'
Response (200 OK) — the new (or matched) user and the created
activation:
{
"activation": {
"id": "9001",
"url": "https://...",
"confirmation_url": "https://..."
},
"user": {
"id": "5667",
"was_user_created": true,
"was_requested_password_applied": false
}
}
The newly created subscription starts in INCOMPLETE state and should
be activated later via the regular activation flow (see the
Activation tag for the confirmation step using the
returned confirmation_url).
If user is omitted and no user with the given partner_id +
external_id exists, the response is 404 Not Found.
Stop the subscription associated with the activation — typically when the partner relationship ends or the user moves to a different product.
curl -X DELETE "https://api.{tenant}.beat.no/v2/partnerusers/activations/<ACTIVATION_ID>" \
-H "X-Auth-Client-Id: <CLIENT_ID>" \
-H "X-Auth-Client-Secret: <CLIENT_SECRET>"
Response (200 OK):
{}
400 Bad Request is returned if the activation has already been
canceled; 404 Not Found if no activation with the given id exists for
this partner.
Primary endpoint for partners to create and associate a user with the partner and add a partner subscription for that user.
user property must be present in the request with a valid
email or msisdn.partner_id + external_id already exists,
the user is not updated.partner_id + external_id exists, look up
the user by email (or msisdn). Create a new user if none is
found; otherwise use the existing user.external_id.INCOMPLETE state and should be
activated later.Authorization: Partner credentials required (X-Auth-Client-Id and X-Auth-Client-Secret). Separate from the OAuth bearer flow used by the rest of the API.
required | object |
object User details used when creating a new user or looking one up by email/msisdn. | |
required | object |
| state | integer Optional. If set to |
{- "partneruser": {
- "external_id": "string"
}, - "user": {
- "email": "string",
- "msisdn": "string",
- "firstname": "string",
- "lastname": "string",
- "username": "string"
}, - "product": {
- "id": "string"
}, - "state": 0
}{- "activation": {
- "id": "string",
- "confirmation_url": "string"
}, - "user": {
- "id": "1234",
- "was_requested_password_applied": true,
- "was_user_created": true
}
}Ends the subscription associated with the given activation for the authenticated partner.
Authorization: Partner credentials required (X-Auth-Client-Id and X-Auth-Client-Secret).
| activation_id required | integer Identifier of the activation to end. |
{ }