Beat Technology Core API Documentation (2.0.0)

Download OpenAPI specification:

License: Commercial

General notes

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.

API consumers

The API is shared by three distinct categories of caller, and some endpoints or authorization rules are written with a specific category in mind:

  1. End-user apps (customers) — web frontends, mobile apps, and set-top boxes. These run in either visitor or authenticated-user mode.
  2. Backoffice app — the internal support tooling.
  3. Partner integrations — server-to-server callers that manage subscriptions on behalf of end users (see the Subscription management walkthrough).

Endpoints

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.

Request basics

Both request and response bodies are UTF-8 encoded.

Content-Type

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.

Data formats

id — string

Every 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 — string

UTC, in the form YYYY-MM-DD (e.g. 1997-07-16).

datetime — string

UTC, 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 year
  • MM — two-digit month (01 = January, …)
  • DD — two-digit day of month (01–31)
  • hh — two digits of hour (00–23), 24-hour clock
  • mm — two digits of minute (00–59)
  • ss — two digits of second (00–59)
  • TZD — time zone designator, always Z

No decimal fraction of a second is used, and +hh:mm / -hh:mm offsets are not accepted — only Z.

url — string

Fully qualified URLs only.

Naming conventions

  • URL/URI path segments and query parameters: lower case, underscores.
  • JSON property names: lower case, underscores.

Pagination

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:

  • Format: unit SP first-pos "-" last-pos "/" (instance-length | "*").
  • A 416 Requested Range Not Satisfiable response SHOULD include Content-Range with * as the range.
  • A 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.

Examples

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

Custom HTTP headers

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.

Content selection

X-Include

Request additional sub-objects to be embedded in the response. The value is a comma-separated list; valid names are:

  • release-reviews
  • release-tracks
  • release-notes
  • release-prices
  • track-prices
  • group-releases
  • group-banners

Image size headers

Several 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-Sizes

Specifies sizes for release cover images.

X-Artist-Image-Sizes

Specifies sizes for artist images.

X-Actor-Image-Sizes

Specifies sizes for actor images.

Stream selection

X-Stream-Formats

Selects the stream quality returned for audio/video resources. The value is a comma-separated list of format names. Valid names are:

  • */high
  • */normal
  • */low
  • h264/*

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-Context

Stream 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

Response bodies are JSON-encoded.

Format conventions

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

HTTP error codes

  • 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.

Error response body

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.

CORS support

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

Subscription management

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).

1. Obtain a client-credentials access token

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.

2. Validate the user's e-mail

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.

3. Create the user 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 $TOKEN here. If you call POST /v2/users with 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.

4. Sign the user in

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.

5. Attach a payment method

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.

5a. Create a setup intent

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.

5b. Look up the tokenized reference

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.

5c. Attach the payment method to the user

$ 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.

6. List available products

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.

7. Activate a subscription

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.).

8. List the user's subscriptions

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.

9. Stop or resume a subscription

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
  }
}

10. Deactivate a subscription immediately

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.

Further reading

  • See the Authentication tag for all supported OAuth grant types, refresh-token handling, and OIDC sign-in.
  • See the User tag for full schemas of the user, credential, migration, and subscription operations referenced above.
  • See the Billing tag for the full setup-intent and payment-method schemas, including Billwerk-specific fields.
  • For partner-specific user-management endpoints (separate, header-based auth), see the Partner users tag.

Actor

Operations around actors

Fetch actors by role

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 services
  • author for audio book services

Pagination 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).

Authorizations:
bearerAuth
query Parameters
role
required
string

Role name to filter by (for example main-artist or author).

header Parameters
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 unit, e.g. actors=0-19.

Responses

Response samples

Content type
application/json
{
  • "actors": [
    ]
}

Upload actor image

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.

Authorizations:
bearerAuth
path Parameters
actor_id
required
string

Identifier of the actor whose image is being uploaded.

Request Body schema: multipart/form-data
required
image
required
string <binary>

JPEG image of the actor.

Responses

Response samples

Content type
application/json
{ }

Artist

Operations around artists

Fetch a single artist

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).

Authorizations:
bearerAuth
path Parameters
artist_id
required
string
header Parameters
X-Artist-Image-Sizes
string

Header specifies sizes for Artist image basic object.

Responses

Response samples

Content type
application/json
{
  • "artist": {
    }
}

Favourite or unfavourite an artist

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.

Authorizations:
bearerAuth
path Parameters
artist_id
required
string
header Parameters
X-Artist-Image-Sizes
string

Header specifies sizes for Artist image basic object.

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.

Request Body schema: application/json
required
favourite
boolean

Responses

Request samples

Content type
application/json
{
  • "favourite": true
}

Response samples

Content type
application/json
{
  • "artist": {
    }
}

Fetch artist biography

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).

Authorizations:
bearerAuth
path Parameters
artist_id
required
string

Responses

Response samples

Content type
application/json
{
  • "bio": {
    }
}

Update artist biography

Replaces the biography content for the given artist. Pass null in content to clear the biography.

Authorization: Editorial admin only.

Authorizations:
bearerAuth
path Parameters
artist_id
required
string
Request Body schema: application/json
required
content
required
string

Full text of the artist biography. The controller also accepts null to clear the existing biography (see drift note on the group).

Responses

Request samples

Content type
application/json
{
  • "content": "string"
}

Response samples

Content type
application/json
{
  • "bio": {
    }
}

Search artists

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).

Authorizations:
bearerAuth
query Parameters
query
required
string

Free-text search string. Must be non-empty.

header Parameters
Range
string

Byte-style range over the artists unit, e.g. artists=20-39 (inclusive).

X-Artist-Image-Sizes
string

Comma-separated list of requested artist image size variants (e.g. w50,h200). See ArtistImage for available sizes.

Responses

Response samples

Content type
application/json
{
  • "artists": [
    ]
}

List top releases for a given artist

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).

Authorizations:
bearerAuth
path Parameters
artist_id
required
string
query Parameters
types
string

Comma-separated list of release types to include. Accepts the shorthand values audio and video:

  • audio is equivalent to album,single
  • video is equivalent to video-album,video-single

See the Release API for the full list of release types.

role
string

Filters releases by the artist's actor role on each release.

header Parameters
Range
string

Byte-style range over the releases unit, e.g. releases=20-39 (inclusive).

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

Responses

Response samples

Content type
application/json
{
  • "releases": [
    ]
}

List top tracks for a given artist

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).

Authorizations:
bearerAuth
path Parameters
artist_id
required
string
query Parameters
role
string

Filters tracks by the artist's actor role on each track.

header Parameters
Range
string

Byte-style range over the tracks unit, e.g. tracks=20-39 (inclusive).

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.

Responses

Response samples

Content type
application/json
{
  • "tracks": [
    ]
}

Authentication

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.

Access Tokens

  • User Access Token — token associated with a user id, requested by one of:
    • grant_type=password
    • grant_type=clone_token
    • grant_type=signed_msisdn
    • grant_type=coupon
    • grant_type=verification_code
    • grant_type=account_user
    • grant_type=openid_handle
  • App Access Token — token not associated with any user, requested by:
    • grant_type=client_credentials

User Tokens

IMPORTANT. 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).

Authentication by User Password (grant_type=password)

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
  }

Authentication by Signed MSISDN (grant_type=signed_msisdn)

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
  }

[DEPRECATED] Authentication by coupon code (grant_type=coupon)

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
  }

Authentication by verification code (grant_type=verification_code)

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
  }

Cross-client Authentication (grant_type=clone_token)

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
  }

Switching between account users (profiles) (grant_type=account_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
}

Authentication by OpenID auth session handle (grant_type=openid_handle)

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

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.

Authentication by Client Credentials (grant_type=client_credentials)

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
  }

Refreshing Tokens (grant_type=refresh_token)

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
  }

Install Referrer support

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
  }

OAuth 2.0 Authentication Flows

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:

  • grant_type=password
  • grant_type=signed_msisdn
  • grant_type=coupon
  • grant_type=verification_code
  • grant_token=clone_token
  • grant_token=account_user
  • grant_token=openid_handle

App Access Token:

  • grant_type=client_credentials

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.

Request Body schema: application/x-www-form-urlencoded
required
grant_type
required
string

Type of grant flow being requested (e.g. password, client_credentials, refresh_token).

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, grant_type=coupon]

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

Responses

Response samples

Content type
application/json
Example
{
  • "access_token": "2YotnFZFEjr1zCsicMWpAA",
  • "token_type": "bearer",
  • "expires_in": 3600,
  • "scope": "read write",
  • "refresh_token": "tGzv3JOkF0XG5Qx2TlKWIA",
  • "user_id": "5667"
}

Create new authentication context

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.

Request Body schema: application/json
required
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.

Responses

Request samples

Content type
application/json
{
  • "partner_id": "string",
  • "redirect_url": "string"
}

Response samples

Content type
application/json
{
  • "context": {
    }
}

Callback for OpenID auth

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.

query Parameters
state
string
code
string

Responses

Response samples

Content type
application/json
{ }

Finish OpenID auth session

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.

Responses

Response samples

Content type
application/json
{
  • "error": "validation_error",
  • "error_description": "The request body failed validation."
}

Authorization

Authorization

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.

Access levels

Public

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.

Any valid bearer token

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).

Logged-in user

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.

Editorial admin

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.

User admin client

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 credentials

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).

Scope-gated bearer token

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``).

HTTP Basic

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).

Multiple accepted access levels

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.

Access level varies by query parameter

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.

Banners

Banner operations

List all banners available to a specific client

Returns a paginated list of banners available to the caller. By default banners pointing to non-existing entities are filtered out; pass filter_empty=false to include them as well.

Authorization: Any valid bearer token (app-only / visitor tokens are accepted).

Authorizations:
bearerAuth
query Parameters
filter_empty
boolean

When true (default), banners that reference non-existing entities are excluded from the response.

header Parameters
X-Actor-Image-Sizes
string

Header specifies sizes for Actor image objects.

X-Artist-Image-Sizes
string

Header specifies sizes for Artist image basic object.

X-Banner-Image-Sizes
string
X-Release-Cover-Sizes
integer

header specifies sizes for Release cover basic objects. See Basic response object section for details.

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-reviews
  • release-tracks
  • release-notes
  • release-prices
  • track-prices
  • group-releases
  • group-banners
Range
string

Responses

Response samples

Content type
application/json
{
  • "banners": [
    ]
}

Create a new banner

Creates a new banner with the supplied link target. Both link_type and link_value are required.

Authorization: Editorial admin only.

Authorizations:
bearerAuth
header Parameters
X-Actor-Image-Sizes
string

Header specifies sizes for Actor image objects.

X-Artist-Image-Sizes
string

Header specifies sizes for Artist image basic object.

X-Banner-Image-Sizes
string
X-Release-Cover-Sizes
integer

header specifies sizes for Release cover basic objects. See Basic response object section for details.

Request Body schema: application/json
required
link_type
required
string
Enum: "release" "artist" "banner-group" "release-group" "series" "url" "paginated-release-group"
link_value
required
string

Responses

Request samples

Content type
application/json
{
  • "link_type": "release",
  • "link_value": "string"
}

Response samples

Content type
application/json
{
  • "banner": {
    }
}

Fetch a banner by ID

Retrieves a single banner by its identifier, including its link target and any configured title, subtitle and overlays.

Authorization: Any valid bearer token (app-only / visitor tokens are accepted).

Authorizations:
bearerAuth
path Parameters
banner_id
required
string
header Parameters
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-Banner-Image-Sizes
string
X-Release-Cover-Sizes
integer

header specifies sizes for Release cover basic objects. See Basic response object section for details.

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-reviews
  • release-tracks
  • release-notes
  • release-prices
  • track-prices
  • group-releases
  • group-banners

Responses

Response samples

Content type
application/json
{
  • "banner": {
    }
}

Update a banner by ID

Updates mutable fields of an existing banner. Both link_type and link_value must be provided together when changing the link target.

Authorization: Editorial admin only.

Authorizations:
bearerAuth
path Parameters
banner_id
required
string
header Parameters
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-Banner-Image-Sizes
string
X-Release-Cover-Sizes
integer

header specifies sizes for Release cover basic objects. See Basic response object section for details.

Request Body schema: application/json
required
link_type
required
string
Enum: "release" "artist" "banner-group" "release-group" "series" "url"
link_value
required
string
title
string
subtitle
string

Responses

Request samples

Content type
application/json
{
  • "link_type": "release",
  • "link_value": "string",
  • "title": "string",
  • "subtitle": "string"
}

Response samples

Content type
application/json
{
  • "banner": {
    }
}

Banner Images

Banner image operations

Upload a banner image

Uploads an image for the given banner. The request must be multipart/form-data with a single image file part.

Authorization: Editorial admin only.

Authorizations:
bearerAuth
path Parameters
banner_id
required
string
Request Body schema: multipart/form-data
required
Schema not provided

Responses

Response samples

Content type
application/json
{
  • "error": "error_not_found",
  • "error_description": "The requested resource was not found."
}

Banner Groups

Banner group operations

List banner groups

Returns a paginated list of banner groups visible to the caller. The optional group_ids query parameter narrows the result to a specific set of groups. By default each group entry contains only banner IDs; set X-Include: group-banners to expand full banner objects inline.

Authorization: Any valid bearer token (app-only / visitor tokens are accepted).

Authorizations:
bearerAuth
query Parameters
group_ids
string

Comma-separated list of banner group IDs to return.

header Parameters
X-Actor-Image-Sizes
string

Header specifies sizes for Actor image objects.

X-Artist-Image-Sizes
string

Header specifies sizes for Artist image basic object.

X-Banner-Image-Sizes
string
X-Release-Cover-Sizes
integer

header specifies sizes for Release cover basic objects. See Basic response object section for details.

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-reviews
  • release-tracks
  • release-notes
  • release-prices
  • track-prices
  • group-releases
  • group-banners
Range
string

Responses

Response samples

Content type
application/json
{
  • "groups": [
    ]
}

Create a new banner group

Creates a new banner group with the supplied metadata. The position field determines the group's ordering relative to other groups.

Authorization: Editorial admin only.

Authorizations:
bearerAuth
header Parameters
X-Actor-Image-Sizes
string

Header specifies sizes for Actor image objects.

X-Artist-Image-Sizes
string

Header specifies sizes for Artist image basic object.

X-Banner-Image-Sizes
string
X-Release-Cover-Sizes
integer

header specifies sizes for Release cover basic objects. See Basic response object section for details.

Request Body schema: application/json
required
name
required
string
visible
required
boolean
position
required
integer
source_link_type
string
source_link_value
string
source_link_filter
string

JSON-encoded string describing the catalog-service filter.

Responses

Request samples

Content type
application/json
{
  • "name": "string",
  • "visible": true,
  • "position": 0,
  • "source_link_type": "string",
  • "source_link_value": "string",
  • "source_link_filter": "string"
}

Response samples

Content type
application/json
{
  • "group": {
    }
}

Fetch a banner group by ID

Retrieves a single banner group by its identifier together with its contained banners. Non-visible groups are hidden from regular users and return 403; editorial admins may fetch them regardless of visibility.

Authorization: Any valid bearer token (app-only / visitor tokens are accepted).

Authorizations:
bearerAuth
path Parameters
group_id
required
string
header Parameters
X-Actor-Image-Sizes
string

Header specifies sizes for Actor image objects.

X-Artist-Image-Sizes
string

Header specifies sizes for Artist image basic object.

X-Banner-Image-Sizes
string
X-Release-Cover-Sizes
integer

header specifies sizes for Release cover basic objects. See Basic response object section for details.

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-reviews
  • release-tracks
  • release-notes
  • release-prices
  • track-prices
  • group-releases
  • group-banners

Responses

Response samples

Content type
application/json
{
  • "group": {
    }
}

Update a banner group by ID

Updates an existing banner group. All request body fields are optional, but at least one must be provided.

Authorization: Editorial admin only.

Authorizations:
bearerAuth
path Parameters
group_id
required
string
header Parameters
X-Actor-Image-Sizes
string

Header specifies sizes for Actor image objects.

X-Artist-Image-Sizes
string

Header specifies sizes for Artist image basic object.

X-Banner-Image-Sizes
string
X-Release-Cover-Sizes
integer

header specifies sizes for Release cover basic objects. See Basic response object section for details.

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-reviews
  • release-tracks
  • release-notes
  • release-prices
  • track-prices
  • group-releases
  • group-banners
Request Body schema: application/json
required
name
string
visible
boolean
source_link_type
string
source_link_value
string
source_link_filter
string

JSON-encoded string describing the catalog-service filter.

Array of objects (group_entry)

Responses

Request samples

Content type
application/json
{
  • "name": "string",
  • "visible": true,
  • "source_link_type": "string",
  • "source_link_value": "string",
  • "source_link_filter": "string",
  • "banners": [
    ]
}

Response samples

Content type
application/json
{
  • "group": {
    }
}

Batch

Batch operation

Execute multiple API requests in one call Deprecated

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:

  • Maximum 20 subrequests per batch.
  • /v2/batch itself cannot be used as a subrequest URL (no nesting).
  • Subrequest headers are merged with the outer request's Authorization, Content-Type, and configured custom headers. Subrequest values take precedence, and empty string values are stripped to avoid downstream validation errors.
  • A failing subrequest does not abort the batch; its error is returned in the corresponding 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).

Authorizations:
bearerAuth
Request Body schema: application/json
required
required
Array of objects <= 20 items

Ordered list of subrequests to execute. Responses are returned in the same order.

Responses

Request samples

Content type
application/json
Example

Fetch featured content and the user's personal data in one round trip.

{
  • "requests": [
    ]
}

Response samples

Content type
application/json
{
  • "responses": [
    ]
}

Billing

Workflow to save card to user account

  1. Authorize user using Auth API
  2. POST v2/billing/setupintents - get key necessary to collect card details on the client side
  3. POST v2/billing/paymentmethods - saves card to user account
  4. Activate product via Migration API

Create a setup intent

Creates 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:

  • For Vipps, product_id is required and redirect_url typically applies.
  • For Reepay and Paystack, both 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.

Authorizations:
bearerAuth
Request Body schema: application/json
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 payment_type. If not set, the setup intent will be created for any payment subtype allowed for the service.

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.

Responses

Request samples

Content type
application/json
{
  • "payment_type": 0,
  • "payment_method_subtype": "card",
  • "product_id": "string",
  • "campaign_code": "string",
  • "redirect_url": "string",
  • "cancel_url": "string",
  • "payment_type_args": {
    }
}

Response samples

Content type
application/json
{
  • "client_secret": "string",
  • "setup_intent": {
    }
}

List saved payment methods

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.

Authorizations:
bearerAuth
query Parameters
setupintent
string

If set, the response is scoped to payment method references created against the specified setup intent.

Responses

Response samples

Content type
application/json
[
  • {
    }
]

Attach a payment method to the user

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.

Authorizations:
bearerAuth
Request Body schema: application/json
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.

Responses

Request samples

Content type
application/json
{
  • "payment_type": 0,
  • "reference": "string"
}

Response samples

Content type
application/json
{
  • "error": "error_not_found",
  • "error_description": "The requested resource was not found."
}

Bookmark

Operations around bookmarks

Create a bookmark

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.

Authorizations:
bearerAuth
header Parameters
X-Change-Timestamp
string

Optional client-supplied timestamp for the change; defaults to the server time if omitted.

Request Body schema: application/json
required

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 audio when omitted.

position
integer

Required when position_type=audio. Seconds since the beginning of the track.

reader_position_selector
string

Required when position_type=ebook. EPUB CFI (Canonical Fragment Identifier).

reader_position_ratio
number <double> [ 0 .. 1 ]

Required when position_type=ebook. Position as a fraction of pages read (range: 0-1).

Responses

Request samples

Content type
application/json
{
  • "entity_type": "track",
  • "entity_id": "string",
  • "note": "string",
  • "position_type": "audio",
  • "position": 0,
  • "reader_position_selector": "epubcfi(/6/2!/0)",
  • "reader_position_ratio": 1
}

Response samples

Content type
application/json
{
  • "bookmark": {
    }
}

Fetch a bookmark by ID

Return the bookmark identified by bookmark_id, provided it belongs to the authenticated user.

Authorization: Logged-in user required.

Authorizations:
bearerAuth
path Parameters
bookmark_id
required
string

Identifier of the bookmark to fetch.

Responses

Response samples

Content type
application/json
{
  • "bookmark": {
    }
}

Update a bookmark by ID

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.

Authorizations:
bearerAuth
path Parameters
bookmark_id
required
string

Identifier of the bookmark to update.

header Parameters
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.

Request Body schema: application/json
required

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 audio when omitted.

position
integer

Required when position_type=audio. Seconds since the beginning of the track.

reader_position_selector
string

Required when position_type=ebook. EPUB CFI (Canonical Fragment Identifier).

reader_position_ratio
number <double> [ 0 .. 1 ]

Required when position_type=ebook. Position as a fraction of pages read (range: 0-1).

Responses

Request samples

Content type
application/json
{
  • "note": "string",
  • "position_type": "audio",
  • "position": 0,
  • "reader_position_selector": "epubcfi(/6/2!/0)",
  • "reader_position_ratio": 1
}

Response samples

Content type
application/json
{
  • "bookmark": {
    }
}

Delete a bookmark by ID

Delete the bookmark identified by bookmark_id. The bookmark must belong to the authenticated user.

Authorization: Logged-in user required.

Authorizations:
bearerAuth
path Parameters
bookmark_id
required
string

Identifier of the bookmark to delete.

header Parameters
X-Change-Timestamp
string

Optional client-supplied timestamp for the change; defaults to the server time if omitted.

Responses

Response samples

Content type
application/json
{
  • "error": "error_not_found",
  • "error_description": "The requested resource was not found."
}

Campaign

Operations around campaigns

Look up a campaign by code

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).

Authorizations:
bearerAuth
query Parameters
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.

header Parameters
Range
string

Optional byte-style range header; included for consistency with paginated endpoints.

Responses

Response samples

Content type
application/json
{
  • "campaigns": [
    ]
}

Charge

Operations around one-off payments

List charges for entities

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).

Authorizations:
bearerAuth
query Parameters
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.

Responses

Response samples

Content type
application/json
{
  • "charges": [
    ]
}

Create a one-time charge

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.

Authorizations:
bearerAuthbearerAuth
Request Body schema: application/json
required
reason
required
string
Enum: "offlining" "coupon" "purchase" "campaign" "external_charge" "vipps_initial_charge" "vipps_renew"

The reason for the charge. If set to external_charge, a user_id must also be set.

Authorization: Baseline for this operation is any valid bearer token. reason=external_charge additionally requires a bearer token with the external-charge scope.

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 track_id, release_id or coupon_id).

payment_type
integer

Payment method identifier. Use 3 for Stripe; see the {User Object} returned from /v2/users for more options.

source
string

May be required for some payment types (for example, a Stripe token).

email
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.

Responses

Request samples

Content type
application/json
{
  • "reason": "offlining",
  • "entity_type": "release",
  • "entity_id": "123",
  • "payment_type": 3,
  • "source": "string",
  • "email": "string",
  • "recipient_name": "string",
  • "message": "string",
  • "amount": 0,
  • "unit": "XCR"
}

Response samples

Content type
application/json
{
  • "id": "string"
}

Cancel an external charge

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.

Authorizations:
bearerAuth
path Parameters
charge_id
required
integer

The ID of the charge to cancel.

Responses

List external charges for a user

Lists charges created with reason=external_charge for the given user, optionally filtered by entity.

Authorization: Bearer token with the external-charge scope.

Authorizations:
bearerAuth
path Parameters
user_id
required
integer
query Parameters
entity_type
required
string
Enum: "coupon" "release" "campaign" "track" "balance"
entity_id
string

Optional. Filter by a specific entity ID.

Responses

Response samples

Content type
application/json
{
  • "charges": [
    ]
}

Coupon

Operations around coupons

Look up a coupon by code

Looks up a coupon by its code and reports whether it is valid for redemption.

  • The valid flag on the returned coupon indicates whether it can currently be redeemed.
  • To redeem a valid coupon, call POST /v2/users/{user_id}/coupons/redemptions.

Authorization: Any valid bearer token (app-only / visitor tokens are accepted).

Authorizations:
bearerAuth
query Parameters
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.

header Parameters
Range
string

Standard pagination range header.

X-Coupon-Offer-Image-Sizes
string

Comma-separated image size tokens (for example w50,h200) that select which sizes are included in the offer image object. When omitted, image fields are returned empty.

Responses

Response samples

Content type
application/json
{
  • "coupons": [
    ]
}

Generate a coupon (gift card)

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).

Authorizations:
bearerAuth
Request Body schema: application/json
required
offer_id
required
string

Identifier of the offer to generate the coupon from. See GET /v2/coupons/offers?type={type}.

Responses

Request samples

Content type
application/json
{
  • "offer_id": "1234"
}

Response samples

Content type
application/json
{
  • "coupon": {
    }
}

List coupon offers

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:

  • List available offers with this endpoint.
  • Generate a gift card from an offer: POST /v2/coupons with offer_id.
  • List the authenticated user's generated gift cards: GET /v2/users/{user_id}/coupons?type=giftcard.
  • Pay for a generated gift card: POST /v2/users/{user_id}/charges with entity_type=coupon and entity_id={coupon_code}.
  • Redeem a coupon: 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).

Authorizations:
bearerAuth
query Parameters
type
required
string

The type of offer to list. Only giftcard is supported.

header Parameters
Range
string

Standard pagination range header.

X-Coupon-Offer-Image-Sizes
string

Comma-separated image size tokens (for example w50,h200) that select which sizes are included in each offer's image object.

Responses

Response samples

Content type
application/json
{
  • "offers": [
    ]
}

Event

Operations around various user events

List global events

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).

Authorizations:
bearerAuth
header Parameters
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. items=0-9).

Responses

Response samples

Content type
application/json
{
  • "events": [
    ]
}

Favourite

Operations around collection of personal favourites

List the authenticated user's favourites filtered by entity ID

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.

Authorizations:
bearerAuth
query Parameters
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.

Responses

Response samples

Content type
application/json
{
  • "favourites": [
    ]
}

Features

Feature operations

List features for the current user

Returns feature flags for the authenticated user.

The response varies depending on the entity_type query parameter:

  • When entity_type is omitted, the endpoint returns the global features associated with the user and their active subscription.
  • When 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.
  • The optional 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).

Authorizations:
bearerAuth
query Parameters
entity_type
string
Enum: "release" "device"

Type of the entities to look up features for. When present, entity_id must also be provided.

  • release — returns per-release access flags (has_online_access, has_offline_access, etc.) using the shared feature schema.
  • device — returns a single can_stream feature for the current device; the response shape differs from release (see the 200 response).
entity_id
Array of strings

Comma-separated list of entity IDs to look up features for. Required when entity_type is provided.

name
string

Comma-separated list of feature names to filter the response by. Only meaningful when entity_type is present.

Responses

Response samples

Content type
application/json
Example
{
  • "features": [
    ]
}

Home Screen

[DEPRECATED] - use v2/layouts/home to fetch content for the home screen.

Integrations

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/

Handle a webhook callback from Stripe

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.

Responses

Response samples

Content type
application/json
{
  • "error": "validation_error",
  • "error_description": "The request body failed validation."
}

Handle a webhook callback from Reepay

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.

Responses

Response samples

Content type
application/json
{
  • "error": "validation_error",
  • "error_description": "The request body failed validation."
}

Handle a webhook callback from Paystack

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.

Responses

Response samples

Content type
application/json
{
  • "error": "validation_error",
  • "error_description": "The request body failed validation."
}

Layouts

This api contain endpoints to construct and fetch layouts for different pages

List layouts

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.

Authorizations:
bearerAuth
header Parameters
Range
string

Range header in the form items=<start>-<end> to request a slice of the collection.

Responses

Response samples

Content type
application/json
{
  • "layouts": [
    ]
}

Get layout by id or alias

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.

Authorizations:
bearerAuth
path Parameters
id
required
string
Enum: "*" "home" "podcasts"

Numeric layout id, or one of the predefined aliases (home, podcasts).

Responses

Response samples

Content type
application/json
{
  • "layout": {
    }
}

Update a layout

Updates a layout identified by its numeric id. Supports renaming the layout and replacing its list of sections wholesale.

Authorization: Editorial admin only.

Authorizations:
bearerAuth
path Parameters
id
required
integer

Numeric layout id.

Request Body schema: application/json
required
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.

Responses

Request samples

Content type
application/json
{
  • "name": "string",
  • "product_id": "string",
  • "region": "string",
  • "profile_type": "string",
  • "sections": [
    ]
}

Response samples

Content type
application/json
{
  • "layout": {
    }
}

List layout conditions

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.

Authorizations:
bearerAuth
path Parameters
id
required
integer

Numeric layout id.

Responses

Response samples

Content type
application/json
{
  • "conditions": [
    ]
}

Replace layout conditions

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.

Authorizations:
bearerAuth
path Parameters
id
required
integer

Numeric layout id.

Request Body schema: application/json
required
Array of objects (layout_condition)

Full replacement list of conditions for the layout.

Responses

Request samples

Content type
application/json
{
  • "conditions": [
    ]
}

Response samples

Content type
application/json
{
  • "conditions": [
    ]
}

LCP

This endpoint can be used to work with LCP-encrypted content.

Generate LCP license

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.

Authorizations:
bearerAuth
path Parameters
release_id
required
integer

Release id.

Request Body schema: application/json
required
purpose
required
string
Value: "export"
password
required
string non-empty

Responses

Request samples

Content type
application/json
{
  • "purpose": "export",
  • "password": "string"
}

Response samples

Content type
application/json
{ }

CORS preflight

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.

Authorizations:
None
path Parameters
release_id
required
integer

Release id.

Responses

Response samples

Content type
application/json
{
  • "error": "error_not_found",
  • "error_description": "The requested resource was not found."
}

Validate LCP license access status

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).

Authorizations:
basicAuth
path Parameters
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.

Responses

Validate LCP license access status (HEAD)

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).

Authorizations:
basicAuth
path Parameters
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.

Responses

CORS preflight for LCP license status

Standard CORS preflight handler for the LCP license status endpoint. No authentication is required for the preflight itself.

Authorizations:
None
path Parameters
release_id
required
integer

Identifier of the LCP-protected release.

user_id
required
integer

Identifier of the user.

Responses

Response samples

Content type
application/json
{ }

Passwords

Operations around passwords

Complete password reset

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.

Authorizations:
bearerAuth
Request Body schema: application/json
required

Exactly one of msisdn or email must be provided and must match the identifier used when the reset was initiated. Backend behaviour:

  • The new password is checked against the configured minimum quality and length requirements.
  • The supplied code is checked against the one stored for the pending reset request created by POST /v2/passwords/requests.
  • On match, the account password is updated to the new value.
msisdn
string

Phone number (MSISDN) of the account whose password is being reset. Mutually exclusive with email; must match the value used when initiating the reset.

email
string

E-mail address of the account whose password is being reset. Mutually exclusive with msisdn; must match the value used when initiating the reset.

code
string

Security code received by SMS or e-mail from the preceding POST /v2/passwords/requests call.

password
string

New password to set on the account. Must satisfy the configured minimum length and strength requirements.

Responses

Request samples

Content type
application/json
{
  • "msisdn": "string",
  • "email": "string",
  • "code": "string",
  • "password": "string"
}

Response samples

Content type
application/json
{
  • "error": "error_not_found",
  • "error_description": "The requested resource was not found."
}

Initiate password reset

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.

Authorizations:
bearerAuth
Request Body schema: application/json
required

Exactly one of msisdn or email must be provided. Backend behaviour:

  • If msisdn is provided, the security code is delivered by SMS.
  • If email is provided, a password reset link containing the code is delivered by e-mail.
  • If 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 email.

email
string

E-mail address of the account to reset. Mutually exclusive with msisdn.

return
boolean

Defaults to false. When set to true, the generated security code is returned in the response body rather than being sent to the end user. Requires the caller to have the return-password-code scope.

Responses

Request samples

Content type
application/json
{
  • "msisdn": "string",
  • "email": "string",
  • "return": true
}

Response samples

Content type
application/json
{
  • "code": "email-token or sms-code"
}

Products

Access to products limited to given access_token/client_id, for instance:

  • End-user apps can only see products available to him.
  • Platform can access everything.

Get product

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).

Authorizations:
bearerAuth
path Parameters
product_id
required
string

Responses

Response samples

Content type
application/json
{
  • "product": {
    }
}

List products

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).

Authorizations:
bearerAuth
header Parameters
Range
string

Responses

Response samples

Content type
application/json
{
  • "products": [
    ]
}

Progress

Operations around progress

List user progress

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.

Authorizations:
bearerAuth
query Parameters
entity_type
string
Enum: "track" "release"

Restrict results to progress on entities of this type. Must be supplied together with entity_id.

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 entity_type.

header Parameters
Range
string

Standard pagination range header (e.g. items=0-49).

Responses

Response samples

Content type
application/json
{
  • "progresses": [
    ]
}

Create or upsert a progress record

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.

Authorizations:
bearerAuth
Request Body schema: application/json
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 stop_position update, in UTC.

position_type
string
Enum: "ebook" "audio"

Kind of position being reported. Defaults to audio.

stop_position
integer

Required if position_type=audio: seconds since the beginning of the entity.

reader_position_selector
string

Required if position_type=ebook: EPUB CFI (Canonical Fragment Identifier) pointing at the reader position.

reader_position_ratio
number <double> [ 0 .. 1 ]

Required if position_type=ebook: reading position as a fraction of pages read (range 0-1).

Responses

Request samples

Content type
application/json
{
  • "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
}

Response samples

Content type
application/json
{
  • "progress": {
    }
}

Fetch progress by ID

Returns a single progress record belonging to the authenticated user.

Authorization: Logged-in user required.

Authorizations:
bearerAuth
path Parameters
progress_id
required
string

Identifier of the progress record to fetch.

Responses

Response samples

Content type
application/json
{
  • "progress": {
    }
}

Update progress by ID

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.

Authorizations:
bearerAuth
path Parameters
progress_id
required
string

Identifier of the progress record to update.

Request Body schema: application/json
required
changed
required
string <Y-m-d H:i:s>

Time of the most recent stop_position update, in UTC.

position_type
string
Enum: "ebook" "audio"

Kind of position being reported. Defaults to audio.

stop_position
integer

Required if position_type=audio: seconds since the beginning of the entity.

reader_position_selector
string

Required if position_type=ebook: EPUB CFI (Canonical Fragment Identifier) pointing at the reader position.

reader_position_ratio
number <double> [ 0 .. 1 ]

Required if position_type=ebook: reading position as a fraction of pages read (range 0-1).

Responses

Request samples

Content type
application/json
{
  • "changed": "string",
  • "position_type": "ebook",
  • "stop_position": 0,
  • "reader_position_selector": "epubcfi(/6/2!/0)",
  • "reader_position_ratio": 1
}

Response samples

Content type
application/json
{
  • "progress": {
    }
}

Delete progress by ID

Deletes a progress record owned by the authenticated user.

Authorization: Logged-in user required.

Authorizations:
bearerAuth
path Parameters
progress_id
required
string

Identifier of the progress record to delete.

Responses

Response samples

Content type
application/json
{
  • "error": "error_not_found",
  • "error_description": "The requested resource was not found."
}

Quotas

Operations around quota

Fetch current user's quotas

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.

Authorizations:
bearerAuth

Responses

Response samples

Content type
application/json
{
  • "quotas": [
    ]
}

Rating

Allows user to rate various entities - releases. tracks, etc.

List the authenticated user's ratings for an entity

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.

Authorizations:
bearerAuth
query Parameters
entity_type
required
string
Value: "release"
Example: entity_type=release

Type of the entity to look up ratings for. Only release is supported by this endpoint; other values are rejected with 400 Bad Request. (The companion POST /v2/ratings endpoint accepts track, release, and artist.)

entity_id
required
string

Identifier of the entity (release) whose ratings should be returned.

header Parameters
Range
string

Standard Range header used for pagination.

Responses

Response samples

Content type
application/json
{
  • "ratings": [
    ]
}

Create a rating

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.

Authorizations:
bearerAuth
header Parameters
X-Change-Timestamp
string

Optional client-supplied timestamp used for change tracking.

Request Body schema: application/json
required
entity_type
required
string
Enum: "track" "release" "artist"

Kind of entity being rated.

entity_id
required
string

corresponds to entity_type

value
required
integer

Rating score, 0-5 stars.

note
string

Optional free-text note attached to the rating.

Responses

Request samples

Content type
application/json
{
  • "entity_type": "track",
  • "entity_id": "track_id, release_id, or artist_id",
  • "value": 0,
  • "note": "string"
}

Response samples

Content type
application/json
{
  • "rating": {
    }
}

Fetch rating by ID

Returns a single rating belonging to the authenticated user.

Authorization: Logged-in user required.

Authorizations:
bearerAuth
path Parameters
rating_id
required
integer

Identifier of the rating to fetch.

Responses

Response samples

Content type
application/json
{
  • "rating": {
    }
}

Update rating by 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.

Authorizations:
bearerAuth
path Parameters
rating_id
required
integer

Identifier of the rating to update.

header Parameters
X-Change-Timestamp
string

Optional client-supplied timestamp used for change tracking.

Request Body schema: application/json
required

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.

Responses

Request samples

Content type
application/json
{
  • "value": 0,
  • "note": "string"
}

Response samples

Content type
application/json
{
  • "rating": {
    }
}

Delete a rating

Deletes a rating owned by the authenticated user.

Authorization: Logged-in user required.

Authorizations:
bearerAuth
path Parameters
rating_id
required
integer

Identifier of the rating to delete.

header Parameters
X-Change-Timestamp
string

Optional client-supplied timestamp used for change tracking.

Responses

Response samples

Content type
application/json
{
  • "error": "error_not_found",
  • "error_description": "The requested resource was not found."
}

Release

Release operations

Get release

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=isbn

Authorization: Any valid bearer token (app-only / visitor tokens are accepted).

Authorizations:
bearerAuth
path Parameters
release_id
required
integer

Release id when no ns is specified, or an identifier of the given namespace otherwise.

query Parameters
ns
string

Identifier namespace. Supported values: isbn.

header Parameters
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-reviews
  • release-tracks
  • release-notes
  • release-prices
  • track-prices
  • group-releases
  • group-banners

Responses

Response samples

Content type
application/json
{
  • "release": {
    }
}

Patch release

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.

Authorizations:
bearerAuth
path Parameters
release_id
required
integer
header Parameters
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:

  • release-reviews
  • release-tracks
  • release-notes
  • release-prices
  • track-prices
  • group-releases
  • group-banners
Request Body schema: application/json
required

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.

Responses

Request samples

Content type
application/json
{
  • "favourite": true
}

Response samples

Content type
application/json
{
  • "release": {
    }
}

List release alternates

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).

Authorizations:
bearerAuth
path Parameters
id
required
string

Release id.

Responses

Response samples

Content type
application/json
{
  • "releases": [
    ]
}

List release bookmarks

Returns a paginated list of bookmarks for the given release (entity_type release). See also the Bookmarks API.

Authorization: Logged-in user required.

Authorizations:
bearerAuth
path Parameters
release_id
required
integer
header Parameters
Range
string

Responses

Response samples

Content type
application/json
{
  • "bookmarks": [
    ]
}

Delete a release group

Deletes the release group identified by group_id.

Authorization: Logged-in user required.

Authorizations:
bearerAuth
path Parameters
group_id
required
string
header Parameters
X-Change-Timestamp
string

Time of change in UTC; defaults to the backend's current time.

Responses

Response samples

Content type
application/json
{
  • "error": "error_not_found",
  • "error_description": "The requested resource was not found."
}

Get a release group

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.

Authorizations:
bearerAuth
path Parameters
group_id
required
string
Enum: "purchased" "borrowed" "finished" "played" "wishlist" "*"

Either a numeric release group id or one of the predefined synthetic aliases (purchased, borrowed, finished, played, wishlist).

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).

header Parameters
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:

  • release-reviews
  • release-tracks
  • release-notes
  • release-prices
  • track-prices
  • group-releases
  • group-banners

Responses

Response samples

Content type
application/json
{
  • "group": {
    }
}

Update a release group

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.

Authorizations:
bearerAuth
path Parameters
group_id
required
string
Enum: "wishlist" "*"

Either a numeric release group id or the predefined alias wishlist.

header Parameters
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
Request Body schema: application/json
required
name
string
visible
boolean
Array of objects (group_entry-2)

May be empty.

Responses

Request samples

Content type
application/json
{
  • "name": "string",
  • "visible": true,
  • "releases": [
    ]
}

Response samples

Content type
application/json
{
  • "group": {
    }
}

Remove a release from a release group

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.

Authorizations:
bearerAuth
path Parameters
group_id
required
string
release_id
required
integer

Responses

Response samples

Content type
application/json
[ ]

List releases in a synthetic release group

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:

  • Default: items are full release base objects.
  • response_type=id: items contain only the release id.

Authorization: Logged-in user required.

Authorizations:
bearerAuth
path Parameters
group_id
required
string
Enum: "purchased" "borrowed" "finished" "played" "wishlist"
query Parameters
release_ids
Array of strings

Comma-separated list of release ids to restrict the response to, limited to 1000 items. Supported with the purchased, borrowed, finished and wishlist synthetic groups.

response_type
string

If set to id, the response contains only release ids.

header Parameters
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-reviews
  • release-tracks
  • release-notes
  • release-prices
  • track-prices
  • group-releases
  • group-banners
Range
string

Responses

Response samples

Content type
application/json
{
  • "releases": [
    ]
}

Add a release to a release group

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.

Authorizations:
bearerAuth
path Parameters
group_id
required
string
Request Body schema: application/json
required
release_id
required
string

Identifier of the release to add to the group.

Responses

Request samples

Content type
application/json
{
  • "release_id": "string"
}

Response samples

Content type
application/json
[ ]

List release groups

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).

Authorizations:
bearerAuth
header Parameters
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:

  • release-reviews
  • release-tracks
  • release-notes
  • release-prices
  • track-prices
  • group-releases
  • group-banners
Range
string

Responses

Response samples

Content type
application/json
{
  • "groups": [
    ]
}

Create a release group

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.

Authorizations:
bearerAuth
header Parameters
X-Change-Timestamp
string

Time of change in UTC; defaults to the backend's current time.

Request Body schema: application/json
required
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.

Responses

Request samples

Content type
application/json
{
  • "name": "string",
  • "description": "string",
  • "releases": [
    ]
}

Response samples

Content type
application/json
{
  • "group": {
    }
}

[DEPRECATED] Reorder release groups Deprecated

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.

Authorizations:
bearerAuth
header Parameters
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:

  • release-reviews
  • release-tracks
  • release-notes
  • release-prices
  • track-prices
  • group-releases
  • group-banners
Request Body schema: application/json
required
Array of objects (Release Group Patch Request)

Groups are reordered according to the natural order of this array.

Responses

Request samples

Content type
application/json
{
  • "groups": [
    ]
}

Response samples

Content type
application/json
{
  • "groups": [
    ]
}

Upload a release group image

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.

Authorizations:
bearerAuth
path Parameters
group_id
required
string
Request Body schema: multipart/form-data
required
object

Multipart form body. The controller reads the uploaded file from the image form field.

Responses

Response samples

Content type
application/json
{ }

List release ratings

Returns a paginated list of user ratings attached to the given release.

Authorization: Any valid bearer token (app-only / visitor tokens are accepted).

Authorizations:
bearerAuth
path Parameters
release_id
required
integer
header Parameters
Range
string

Responses

Response samples

Content type
application/json
{
  • "ratings": [
    ]
}

List bookmarks across a release's tracks

Returns a paginated list of bookmarks (entity_type track) across all tracks of the given release.

Authorization: Logged-in user required.

Authorizations:
bearerAuth
path Parameters
release_id
required
integer
header Parameters
Range
string

Responses

Response samples

Content type
application/json
{
  • "bookmarks": [
    ]
}

[DEPRECATED] List progresses across a release's tracks Deprecated

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.

Authorizations:
bearerAuth
path Parameters
release_id
required
integer
header Parameters
Range
string

Responses

Response samples

Content type
application/json
{
  • "progresses": [
    ]
}

Get release by UPC code

Looks up a release by its Universal Product Code.

Authorization: Any valid bearer token (app-only / visitor tokens are accepted).

Authorizations:
bearerAuth
path Parameters
upc_code
required
string
Example: 0724382304258
header Parameters
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.

Responses

Response samples

Content type
application/json
{
  • "release": {
    }
}

Search and filter releases

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).

Authorizations:
bearerAuth
query Parameters
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 media_available_from (YYYY-MM-DD). Dates in the future are clamped to today.

licensor_id
string

Optional licensor id filter; only honored together with media_available_from.

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).

header Parameters
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-reviews
  • release-tracks
  • release-notes
  • release-prices
  • track-prices
  • group-releases
  • group-banners
Range
string
Example: releases=20-39

Pagination range, e.g. releases=20-39 (inclusive). For series_id queries, release_number=<min>-<max> is also accepted.

Responses

Response samples

Content type
application/json
{
  • "releases": [
    ]
}

Reports

Operations around reports

File a player report (deprecated) Deprecated

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).

Authorizations:
bearerAuth
Request Body schema: application/json
required

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

Responses

Request samples

Content type
application/json
{ }

Response samples

Content type
application/json
{
  • "error": "error_not_found",
  • "error_description": "The requested resource was not found."
}

Report player and reader events

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

  • [DEPRECATED] POST /v2/player/reports - still functional but deprecated in favour of more generic POST /v2/reports
  • POST /v2/reports - accepts all types of reports listed below

Reports

  • [DEPRECATED] played-offline - in use only in Motitech
  • play.started - track-based report when player starts playing a new track in music services
  • play.ended - track-based report, mandatory for clients using /v2/streams/online and /v2/streams/offline endpoints to fetch a stream url
  • [DEPRECATED] play.progress - track-based playback progress tracking in audiobook services.
  • play.error - track-based report when playing the current track fails

New event format

Important! These events require action to be set instead of event.

  • player.progress - track-/release-based report for tracking playback in audiobook services
  • reader.progress - track-/release-based report for tracking reading in ebook services.
  • reader.consumed - release-based report for when a release has been consumed
  • release.finished - release-based report for a release being finished

Versioning

  • version 1 -> version 3
  • We skip version 2 because it will be used internally.
  • Important change is that we require 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).

Authorizations:
bearerAuth
Request Body schema: application/json
required
One of
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 20% slower than normal - 1.1 means 10% faster than normal

entity_type
required
string
Enum: "track" "release"
entity_id
required
string

corresponds to entity_type, one of: 'track_id'|'release_id'

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

Responses

Request samples

Content type
application/json
Example

play.ended report

Report play.ended event.

  • Event MUST be reported when playing of current track is over by any reason:
    1. player switches to the next track
    2. user skips to the next track in a play queue
    3. current playing track ends and it's last in the play queue
  • Event SHOULD NOT be reported when:
    1. user pauses the playback
    2. user seeks to the new time within the track
  • Request requires User token

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"
}

Response samples

Content type
application/json
{
  • "error": "error_not_found",
  • "error_description": "The requested resource was not found."
}

Metadata

Free-form per-user key/value metadata. Used to persist client-side preferences and integration state that does not warrant a dedicated schema.

Series

Operations around series

Search for series

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).

Authorizations:
bearerAuth
query Parameters
query
string
header Parameters
X-Series-Image-Sizes
string
Range
string

Responses

Response samples

Content type
application/json
{
  • "series": [
    ]
}

Get a series by id

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).

Authorizations:
bearerAuth
path Parameters
series_id
required
string
header Parameters
X-Series-Image-Sizes
string

Responses

Response samples

Content type
application/json
{
  • "series": {
    }
}

Update a series (deprecated) Deprecated

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.

Authorizations:
bearerAuth
path Parameters
series_id
required
string
header Parameters
X-Series-Image-Sizes
string
Request Body schema: application/json
required
name
string

New display name for the series.

description
string

New description text for the series.

Responses

Request samples

Content type
application/json
{
  • "name": "string",
  • "description": "string"
}

Response samples

Content type
application/json
{
  • "series": {
    }
}

Upload a series image

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.

Authorizations:
bearerAuth
path Parameters
series_id
required
string
Request Body schema: multipart/form-data
required
image
string <binary>

JPEG image of the series.

Responses

Response samples

Content type
application/json
{ }

Streams

X-Stream-Formats header

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.

X-Stream-Context header

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.

Get a short preview 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:

  • Preview by track id: GET /v2/streams/previews/{track_id}
  • Preview by release id: GET /v2/streams/previews/{release_id}?ns=release_id

Authorization: Any valid bearer token (app-only / visitor tokens are accepted).

Authorizations:
bearerAuth
path Parameters
id
required
string

Track ID when ns is not specified, or release ID when ns=release_id.

query Parameters
ns
string

Namespace of the id path parameter. Only release_id is currently supported; omit the parameter to look up by track ID.

Responses

Response samples

Content type
application/json
{
  • "stream": {
    }
}

Get online stream URL for a track

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).

Authorizations:
bearerAuth
path Parameters
track_id
required
integer

Numeric identifier of the track to stream.

header Parameters
X-Stream-Formats
Array of strings

Header specifies stream quality. See v2/streams/online and v2/streams/ofline for details. The value is a comma-separated list of object names.

Valid names are:

  • */high
  • */normal
  • */low
  • h264/*

Header value should go from streams object of Track Extended object - see GET v2/tracks/:track_id for details.

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 X-Stream-Context: <entity_type>/<entity_id> in order to fetch full stream.

Responses

Response samples

Content type
application/json
{
  • "stream": {
    }
}

Get offline stream URL for a track

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).

Authorizations:
bearerAuth
path Parameters
track_id
required
integer

Numeric identifier of the track to stream.

header Parameters
X-Stream-Formats
Array of strings

Header specifies stream quality. See v2/streams/online and v2/streams/ofline for details. The value is a comma-separated list of object names.

Valid names are:

  • */high
  • */normal
  • */low
  • h264/*

Header value should go from streams object of Track Extended object - see GET v2/tracks/:track_id for details.

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 X-Stream-Context: <entity_type>/<entity_id> in order to fetch full stream.

Responses

Response samples

Content type
application/json
{
  • "stream": {
    }
}

Get streams for all tracks in a release

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).

Authorizations:
bearerAuth
path Parameters
release_id
required
integer

Numeric identifier of the release whose tracks should be streamed.

header Parameters
X-Stream-Formats
Array of strings

Header specifies stream quality. See v2/streams/online and v2/streams/ofline for details. The value is a comma-separated list of object names.

Valid names are:

  • */high
  • */normal
  • */low
  • h264/*

Header value should go from streams object of Track Extended object - see GET v2/tracks/:track_id for details.

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 X-Stream-Context: <entity_type>/<entity_id> in order to fetch full stream.

Responses

Response samples

Content type
application/json
{
  • "track": {
    },
  • "streams": {
    }
}

Track

Operations around tracks

Search tracks

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).

Authorizations:
bearerAuth
query Parameters
query
required
string

Free-text search query. Must be non-empty.

header Parameters
Range
string

Pagination range, e.g. tracks=20-39 (inclusive).

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.

Responses

Response samples

Content type
application/json
{
  • "tracks": [
    ]
}

Get a single track

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).

Authorizations:
bearerAuth
path Parameters
track_id
required
integer

Identifier of the track to retrieve.

header Parameters
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-prices, track-streams.

Responses

Response samples

Content type
application/json
{
  • "track": {
    }
}

Favourite or unfavourite a track

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.

Authorizations:
bearerAuth
path Parameters
track_id
required
integer

Identifier of the track to patch.

header Parameters
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-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-prices, track-streams.

Request Body schema: application/json
required

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.

Responses

Request samples

Content type
application/json
{
  • "favourite": true
}

Response samples

Content type
application/json
{
  • "track": {
    }
}

List bookmarks on a track

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.

Authorizations:
bearerAuth
path Parameters
track_id
required
integer

Identifier of the track whose bookmarks should be listed.

header Parameters
Range
string

Pagination range, e.g. bookmarks=20-39 (inclusive).

Responses

Response samples

Content type
application/json
{
  • "bookmarks": [
    ]
}

[DEPRECATED] Get the authenticated user's progress for a track Deprecated

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.

Authorizations:
bearerAuth
path Parameters
track_id
required
integer

Identifier of the track to fetch progress for.

Responses

Response samples

Content type
application/json
{
  • "progress": {
    }
}

User

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_id referenced below is that user's id. With a client-credentials token, the :user_id must be supplied explicitly and the client must be a user admin client for cross-user operations.

Lookup, search, list users

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>"

CRUD on a single user

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>"

Friends

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>"

User credentials

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.

User events

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"

User Changes API

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:

Initial sync

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>

Incremental sync — push local changes

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:

  • Load the latest change record for the target object (record with the max change_id for the given user, entry_type, and entry_id) and capture latest_change_id and latest_change_timestamp.
  • Solve the merge conflict — accept or reject the client change:
    • If base_change_id == latest_change_id, accept the change.
    • If base_change_id < latest_change_id, resolve the conflict between the change from the request and the one already on the server:
      • Compare the change timestamp from the request against latest_change_timestamp.
      • Rule: LATEST CHANGE WINS.
      • Timestamps must be in UTC.
    • If base_change_id > latest_change_id, client error — return 400 Bad Request.
  • If the change has been accepted:
    • Add a new change record and capture new_change_id.
    • Apply the change.
  • Return the changed object and add the 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.

Incremental sync — pull remote changes

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.

User Subscriptions API

Inspect and manipulate the user's running subscriptions:

See the Subscription management walkthrough for end-to-end examples.

Subscription states

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 users

Search for users. The shape of the returned user objects depends on the query parameters provided:

  • With email or msisdn set, or account_users=true, an extended user object is returned (restricted to user admins or the authenticated account).
  • With 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.

Authorizations:
bearerAuth
query Parameters
email
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.

external_provider_id
string

Search by external id. Must be specified together with external_user_id.

header Parameters
Range
string

Responses

Response samples

Content type
application/json
Example
{
  • "users": [
    ]
}

Add user (profile)

Create a new user. This endpoint covers several use cases:

  • Normal signup (request includes an app token — visitor mode):
    • Creates a brand new account.
    • Creates a brand new user.
    • Adds the user as the master-user of the account.
  • Adding a profile-user to an existing account (request includes a user token — user mode):
    • Looks up the existing account from the provided user token.
    • Adds the user as a profile-user on that account.
  • Admin user creation (request is made by a user admin client):
    • Bypasses email_token verification — the email is automatically marked as verified.
    • Allows setting password and msisdn together (normally disallowed).
    • A random password is generated if none is provided.

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.

Authorizations:
bearerAuth
Request Body schema: application/json

A random password will be generated for the account if none is provided.

msisdn
string
firstname
string
lastname
string
username
string
email
string
password
string

Password should not appear if msisdn is present (unless the caller is a user admin client).

newsletter
boolean
Default: false
intent
string
Enum: "webshop" "subscription"

Distinguishes the purpose of user creation within the same client. One of webshop or subscription.

profile_type
string
Enum: "standard" "child"
email_token
string

Email verification token. Requires email to be set. Not required for user admin clients — the email is automatically verified.

avatar_id
string
region
string

The region that the user belongs to.

Responses

Request samples

Content type
application/json
{
  • "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"
}

Response samples

Content type
application/json
{
  • "user": {
    }
}

Delete user (profile)

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.

Authorizations:
bearerAuth
path Parameters
user_id
required
integer

Responses

Response samples

Content type
application/json
{ }

Patch user

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).

Authorizations:
bearerAuth
path Parameters
user_id
required
integer
header Parameters
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
Request Body schema: application/json
required

All parameters are optional, but at least one of them should be present.

firstname
string
lastname
string
email
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"

Responses

Request samples

Content type
application/json
{
  • "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"
}

Response samples

Content type
application/json
{
  • "user": {
    }
}

Get user

Get user account info (excluding any credentials such as password).

Authorization: Logged-in user, or user admin client.

Authorizations:
bearerAuth
path Parameters
user_id
required
integer
header Parameters
X-User-Image-Sizes
string

Responses

Response samples

Content type
application/json
{
  • "user": {
    }
}

GDPR delete user

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.

Authorizations:
bearerAuth
path Parameters
user_id
required
integer

The internal Beat user ID of the user to delete. Use GET /v2/users?external_provider_id=X&external_user_id=Y to resolve an external id to this value.

Responses

Response samples

Content type
application/json
{
  • "message": "User was already deleted previously."
}

[DEPRECATED] Attach credit card to Stripe account Deprecated

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.

Authorizations:
bearerAuth
path Parameters
user_id
required
integer
Request Body schema: application/json
required
token
required
string

Credit card token issued by the Stripe JS SDK.

Responses

Request samples

Content type
application/json
{
  • "token": "string"
}

Response samples

Content type
application/json
{ }

Get personal changes

Fetches the user's personal change feed.

  • [DEPRECATED] Initial fetch GET /v2/users/:user_id/changes returns all personal changes.
  • Sequential fetch 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.

Authorizations:
bearerAuth
path Parameters
user_id
required
integer
query Parameters
base_change_id
string
header Parameters
Range
string

e.g. changes=0-99 to fetch the first 100 changes.

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:

  • release-reviews
  • release-tracks
  • release-notes
  • release-prices
  • track-prices
  • group-releases
  • group-banners

Responses

Response samples

Content type
application/json
{
  • "changes": [
    ]
}

Get latest change id

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.

Authorizations:
bearerAuth
path Parameters
user_id
required
integer

Responses

Response samples

Content type
application/json
{
  • "error": "validation_error",
  • "error_description": "The request body failed validation."
}

List user coupons (gift cards)

Lists coupons owned by the user. Supports regular pagination via the Range header.

Authorization: Logged-in user required.

Authorizations:
bearerAuth
path Parameters
user_id
required
integer
query Parameters
type
required
string

Type of coupons to list. Currently only giftcard is supported.

header Parameters
X-Coupon-Offer-Image-Sizes
string
Range
string

Responses

Response samples

Content type
application/json
{
  • "coupons": [
    ]
}

List the authenticated user's coupon redemptions

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.

Authorizations:
bearerAuth
path Parameters
user_id
required
integer

Identifier of the user whose redemptions to list.

header Parameters
Range
string

Range header in the form items=<start>-<end> to request a slice of the collection.

Responses

Response samples

Content type
application/json
{
  • "redemptions": [
    ]
}

Redeem coupon

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.

Authorizations:
bearerAuth
path Parameters
user_id
required
string
Request Body schema: application/json
required
coupon
string

Responses

Request samples

Content type
application/json
{
  • "coupon": "string"
}

Response samples

Content type
application/json
{
  • "error": "error_not_found",
  • "error_description": "The requested resource was not found."
}

Add credential

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.

Authorizations:
bearerAuth
path Parameters
user_id
required
integer
Request Body schema: application/json
required
type
required
integer
Enum: 5 6 7 8 9 10

Credential type. One of:

  1. Stripe customer id
  2. Bokbasen email
  3. Bokbasen ddsid
  4. User email
  5. User unverified msisdn
  6. Paystack customer id
credential
required
string

Responses

Request samples

Content type
application/json
{
  • "type": 5,
  • "credential": "string"
}

Response samples

Content type
application/json
{
  • "error": "error_not_found",
  • "error_description": "The requested resource was not found."
}

Initiate credential verification (no user context)

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).

Authorizations:
bearerAuth
Request Body schema: application/json
required
type
required
integer
Enum: 6 8

Numeric credential type identifier (see UserCredential::TYPE_*). Supported values:

  • 6 — Bokbasen e-mail (searches the Bokbasen account upstream)
  • 8 — regular user e-mail

Must correspond to a type that has a verification method configured on the server. Unsupported types are rejected with 400 Bad Request.

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.

Responses

Request samples

Content type
application/json
{
  • "type": 8,
  • "credential": "user@example.com"
}

Response samples

Content type
application/json
{ }

Verify added credential

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).

Authorizations:
bearerAuth
path Parameters
user_id
required
integer
Request Body schema: application/json
required
token
string
type
integer
Enum: 5 6 7 8 9 10

Credential type. One of:

  1. Stripe customer id
  2. Bokbasen email
  3. Bokbasen ddsid
  4. User email
  5. User unverified msisdn
  6. Paystack customer id

Responses

Request samples

Content type
application/json
{
  • "token": "string",
  • "type": 5
}

Response samples

Content type
application/json
{ }

List user events

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.

Authorizations:
bearerAuth
path Parameters
user_id
required
integer
header Parameters
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.

Responses

Response samples

Content type
application/json
{
  • "events": [
    ]
}

List user favouritees

Lists the users who have favourited the given user.

Authorization: Logged-in user required.

Authorizations:
bearerAuth
path Parameters
user_id
required
integer
header Parameters
Range
string

Responses

Response samples

Content type
application/json
{
  • "users": [
    ]
}

List favourite artists

Lists the artists the user has favourited.

Authorization: Logged-in user required.

Authorizations:
bearerAuth
path Parameters
user_id
required
integer
header Parameters
X-Artist-Image-Sizes
string

Header specifies sizes for Artist image basic object.

Range
string

Responses

Response samples

Content type
application/json
{
  • "artists": [
    ]
}

List favourite releases

Lists the releases the user has favourited.

Authorization: Logged-in user required.

Authorizations:
bearerAuth
path Parameters
user_id
required
integer
query Parameters
types
string

Comma-separated list of release types. May include shortened audio or video values:

  • audio is equivalent to album,single.
  • video is equivalent to video-album,video-single.

See the Release API for details.

header Parameters
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:

  • release-reviews
  • release-tracks
  • release-notes
  • release-prices
  • track-prices
  • group-releases
  • group-banners

Responses

Response samples

Content type
application/json
{
  • "releases": [
    ]
}

List favourite tracks

Lists the tracks the user has favourited.

Authorization: Logged-in user required.

Authorizations:
bearerAuth
path Parameters
user_id
required
integer
header Parameters
Range
string
X-Actor-Image-Sizes
string

Header specifies sizes for Actor image objects.

Responses

Response samples

Content type
application/json
{
  • "tracks": [
    ]
}

List favourite users

Lists the users that the given user has favourited.

Authorization: Logged-in user required.

Authorizations:
bearerAuth
path Parameters
user_id
required
integer
header Parameters
Range
string

Responses

Response samples

Content type
application/json
{
  • "users": [
    ]
}

Get a user's metadata

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.

Authorizations:
bearerAuth
path Parameters
user_id
required
integer

Identifier of the target user.

Responses

Response samples

Content type
application/json
{
  • "property1": "string",
  • "property2": "string"
}

Upsert entries in a user's metadata bag

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:

  • Keys: maximum 40 characters.
  • Values: maximum 500 characters.
  • Total keys per user: maximum 50 (the full post-merge key count is checked; a request that would push the user over the limit is rejected with 409 Conflict).

Authorization: User admin client only. Other callers, including the target user themselves, receive 400 Bad Request with "Insufficient permissions".

Authorizations:
bearerAuth
path Parameters
user_id
required
integer

Identifier of the target user.

Request Body schema: application/json
required

Key/value pairs to merge into the user's metadata bag.

property name*
additional property
string <= 500 characters

Responses

Request samples

Content type
application/json
{
  • "device_id": "abc-123",
  • "app_variant": "premium"
}

Response samples

Content type
application/json
{ }

Delete a single metadata entry

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".

Authorizations:
bearerAuth
path Parameters
user_id
required
integer

Identifier of the target user.

key
required
string <= 40 characters

Metadata key to delete.

Responses

Response samples

Content type
application/json
{ }

Migrate to product / activate subscription

Activate a subscription based on the given product id (upgrade or downgrade logic).

Authorization: Logged-in user required.

Authorizations:
bearerAuth
path Parameters
user_id
required
integer
Request Body schema: application/json
required
product_id
required
string
renewable
boolean

Whether the new subscription should renew. Defaults to true.

utm_campaign
string

UTM campaign name. May adjust the subscription trial period if specified.

confirmed
boolean

Defaults to true. If false, the request may return 403 along with the URL of an external confirmation/consent page.

metadata
object <json>

A JSON structure for associating information with the subscription.

Responses

Request samples

Content type
application/json
{
  • "product_id": "string",
  • "renewable": true,
  • "utm_campaign": "string",
  • "confirmed": true,
  • "metadata": { }
}

Response samples

Content type
application/json
{ }

[DEPRECATED] Get favourite releases Deprecated

Deprecated alias for GET /v2/users/{user_id}/favourites/releases. Use the newer endpoint in new integrations.

Known clients still using this route:

  • Latest iOS app builds where the endpoint is in use: (unknown).
  • Latest Android app builds where the endpoint is in use: v2.3.5.

Authorization: Logged-in user required.

Authorizations:
bearerAuth
path Parameters
user_id
required
integer
header Parameters
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:

  • release-reviews
  • release-tracks
  • release-notes
  • release-prices
  • track-prices
  • group-releases
  • group-banners

Responses

Response samples

Content type
application/json
{
  • "releases": [
    ]
}

Get tracking identifier for user

Returns a tracking identifier that can be used for the user for analytics or advertising purposes.

Authorization: Logged-in user required.

Authorizations:
bearerAuth
path Parameters
user_id
required
integer

Responses

Response samples

Content type
application/json
{
  • "tracking": {
    }
}

List subscriptions

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.

Authorizations:
bearerAuth
path Parameters
user_id
required
integer
query Parameters
state
string

If specified, returns subscriptions filtered by state. Use state=all to fetch subscriptions in any state.

header Parameters
Range
string

Responses

Response samples

Content type
application/json
{
  • "subscriptions": [
    ]
}

Update a subscription

Stop or resume a subscription. Only the subscription's owner may call this endpoint.

Authorization: Logged-in user required.

Authorizations:
bearerAuth
path Parameters
user_id
required
integer
subscription_id
required
string
Request Body schema: application/json
required
state
required
integer

Target state. Only two transitions are allowed:

  • 6 — stop the subscription (change state to STOPPED).
  • 3 — resume a stopped subscription (change state back to ACTIVE).

All other values are rejected.

comment
string

Optional feedback when the user stops the subscription.

Responses

Request samples

Content type
application/json
{
  • "state": 0,
  • "comment": "string"
}

Response samples

Content type
application/json
{
  • "subscription": {
    }
}

Deactivate a subscription

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.

Authorizations:
bearerAuth
path Parameters
user_id
required
integer
subscription_id
required
string

Responses

Response samples

Content type
application/json
{
  • "error": "error_not_found",
  • "error_description": "The requested resource was not found."
}

Get user balances

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.

Authorizations:
bearerAuth
path Parameters
user_id
integer
header Parameters
Range
string

Responses

Response samples

Content type
application/json
{
  • "balances": [
    ]
}

[DEPRECATED] Charge user Deprecated

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.

Authorizations:
bearerAuthbearerAuth
path Parameters
user_id
required
integer
Request Body schema: application/json
required

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
email
string
recipient_name
string
message
string
amount
integer
unit
string
Enum: "XCR" "EUR"

Responses

Request samples

Content type
application/json
{
  • "reason": "offlining",
  • "entity_type": "track",
  • "entity_id": "string",
  • "payment_type": 0,
  • "source": "string",
  • "email": "string",
  • "recipient_name": "string",
  • "message": "string",
  • "amount": 0,
  • "unit": "XCR"
}

Response samples

Content type
application/json
{
  • "id": "string"
}

List personal release groups

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.

Authorizations:
bearerAuth
path Parameters
user_id
required
integer
header Parameters
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:

  • release-reviews
  • release-tracks
  • release-notes
  • release-prices
  • track-prices
  • group-releases
  • group-banners

Responses

Response samples

Content type
application/json
{
  • "groups": [
    ]
}

Get a user's synthetic release group

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.

Authorizations:
bearerAuth
path Parameters
user_id
required
integer
synthetic
required
string
Enum: "purchased" "borrowed" "finished" "played" "wishlist"
header Parameters
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:

  • release-reviews
  • release-tracks
  • release-notes
  • release-prices
  • track-prices
  • group-releases
  • group-banners

Responses

Response samples

Content type
application/json
{
  • "group": {
    }
}

Add a release to a user's release group

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.

Authorizations:
bearerAuth
path Parameters
user_id
required
integer
group_id
required
string
header Parameters
X-Change-Timestamp
string
Request Body schema: application/json
required

Identifier of the release to add to the group.

id
required
string

Identifier of the release to add.

Responses

Request samples

Content type
application/json
{
  • "id": "string"
}

Response samples

Content type
application/json
{
  • "id": "string"
}

Activation

These endpoints should be used to get activations and activate partner subscriptions.

Confirm an activation

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.

Authorizations:
bearerAuth
path Parameters
activation_id
required
integer

Identifier of the activation to confirm.

Request Body schema: application/json
required
state
required
string
Value: "CONFIRMED"

Target state. Must be CONFIRMED; any other value results in a 400 response.

Responses

Request samples

Content type
application/json
{
  • "state": "CONFIRMED"
}

Response samples

Content type
application/json
{ }

Get activation status by confirmation code

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).

Authorizations:
bearerAuth
query Parameters
confirmation_code
required
string

One-time confirmation code from the activation link.

Responses

Response samples

Content type
application/json
{
  • "activations": [
    ]
}

Partner users

Partner users API

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.

Authentication

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.

Endpoints

Create / activate a partner user

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.

End a partner subscription

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.

Associate a user with the current partner

Primary endpoint for partners to create and associate a user with the partner and add a partner subscription for that user.

Use cases

  • Create a new user and add a partner subscription.
    • The user property must be present in the request with a valid email or msisdn.
  • Add a new partner subscription to an existing user who has no active partner subscription.
  • Migrate an existing user with an active partner subscription to a different product.

Flow

  • Create a user if one does not already exist.
    • If a user with this partner_id + external_id already exists, the user is not updated.
    • If no user with this 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.
  • Associate the user with external_id.
  • Create a subscription for the user.
    • If no subscription exists, create a new one.
    • If a subscription exists for this partner for a different product, end the previous one and create a new one.
    • If a subscription exists for this partner for the same product, do nothing.
  • A newly created subscription has 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.

Authorizations:
(partnerClientIdpartnerClientSecret)
Request Body schema: application/json
required
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 2 and the user already has a running subscription for this partner, no confirmation is required.

Responses

Request samples

Content type
application/json
{
  • "partneruser": {
    },
  • "user": {
    },
  • "product": {
    },
  • "state": 0
}

Response samples

Content type
application/json
{
  • "activation": {
    },
  • "user": {
    }
}

End a partner user's subscription

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).

Authorizations:
(partnerClientIdpartnerClientSecret)
path Parameters
activation_id
required
integer

Identifier of the activation to end.

Responses

Response samples

Content type
application/json
{ }