Profiling

Persisted MusiProfile generations under /v1/profiling/profiles.

Overview

Use MusiProfile to generate an aggregate listener profile from a set of analysed tracks, such as a playlist or a selection from your catalogue, and keep it as organisation history. Create with POST /v1/profiling/profiles, list with GET /v1/profiling/profiles, and retrieve one with GET /v1/profiling/profiles/{profile_id}. For the product behind this API, see the MusiProfile product page.

At least 5 analysed tracks

A profile needs at least 5 distinct eligible tracks. A track is eligible when it is found and has completed MusiTag analysis with the tag data the requested profiles use. Tracks that are not found, duplicates of the same recording, and tracks without that data do not count. With fewer than 5, no profile is generated and the request returns HTTP 422.

Endpoints

  • POST /v1/profiling/profiles: generate and persist an aggregate profile.
  • GET /v1/profiling/profiles: list your organisation's profile history (paginated).
  • GET /v1/profiling/profiles/{profile_id}: retrieve one persisted profile.

Authentication

OAuth client credentials with one of these scopes. See Authentication for the token flow.

  • profiling.write: create a persisted profile generation (consumes profiling credits).
  • profiling.read: list and retrieve persisted profiles (reads do not consume credits).

Request

Body fields

  • tracks (required): array of track items, see Track identifiers.
  • idempotency_key (required): a string you choose, at most 128 characters, unique per generation. Sending a key again returns the generation already stored under it, whatever its status, and does not consume another credit. Use a new key, for example a UUID, for each new generation.
  • catalog_id: one of your organisation's catalogues. Required unless your OAuth client is bound to a catalogue, in which case the bound catalogue is used. List your catalogues with Catalogues.
  • profiles (optional): profile families to compute. When omitted, all families are returned: musical, musical_abridged, ocean, mbti, enneagram, ego_equilibrium, ego_description.

Track identifiers

Each item in tracks must include exactly one of:

  • musimap_uid: MusiMap track UUID, the id returned by the Workspace and MusiMap Atlas track endpoints.
  • isrc: ISRC of the recording.
  • outer_id: your own identifier for a track in your catalogue.

musimap_uid and isrc can reference any recording MusiMap has analysed, so a playlist may include tracks that are not in your catalogue. Tracks in the selected catalogue are matched first. outer_id is matched only within your selected catalogue. Only the aggregate profile is returned; no track-level data is.

Create a persisted profile

Request

curl -X POST "https://api.musimap.com/v1/profiling/profiles" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d @- <<EOF
{
  "idempotency_key": "$(uuidgen)",
  "catalog_id": "$CATALOG_ID",
  "profiles": ["musical", "ocean"],
  "tracks": [
    { "musimap_uid": "$TRACK_ID_1" },
    { "musimap_uid": "$TRACK_ID_2" },
    { "isrc": "GBUM71904911" },
    { "isrc": "USUM71703861" },
    { "outer_id": "client-track-42" }
  ]
}
EOF

Response

A successful create returns HTTP 200 with the standard envelope. The data object is the persisted generation: its id, status and the aggregate profiles.

Response

{
  "status": 200,
  "message": "OK",
  "data": {
    "id": "<profile_id>",
    "status": "completed",
    "catalog_id": "<catalog_id>",
    "scope_type": "catalog",
    "profiles_requested": ["musical", "ocean"],
    "source_track_count": 5,
    "created_at": "<iso8601>",
    "completed_at": "<iso8601>",
    "profiles": {
      "musical": { "...": "aggregate result for this profile family" },
      "ocean": { "...": "aggregate result for this profile family" }
    }
  }
}
  • id: persisted generation id. It is the {profile_id} path value for retrieval.
  • status: completed for a successful generation; failed when a generation did not complete (then error_code and error_message are present and profiles is empty).
  • source_track_count: number of distinct track identifiers you submitted, not the number of eligible tracks.
  • profiles: aggregate results keyed by profile family. The inner structure is per family; the OpenAPI spec declares this map as open-ended.

Credits

Each create consumes one profiling credit. The credit is refunded when the generation fails, including fewer than 5 eligible tracks, and when the new profile is identical to your current one for that catalogue. Replaying an idempotency_key does not consume a credit. See Credits.

List profile history

Returns your organisation's generations, newest first, including failed ones.

Request

curl "https://api.musimap.com/v1/profiling/profiles?page=1&page_size=20" \
  -H "Authorization: Bearer $ACCESS_TOKEN"

Response

{
  "status": 200,
  "message": "OK",
  "data": {
    "count": 1,
    "page": 1,
    "page_size": 20,
    "total_pages": 1,
    "has_next": false,
    "has_previous": false,
    "results": [
      {
        "id": "<profile_id>",
        "status": "completed",
        "catalog_id": "<catalog_id>",
        "scope_type": "catalog",
        "source_track_count": 5,
        "profile_family_count": 2,
        "created_at": "<iso8601>",
        "completed_at": "<iso8601>",
        "error_code": null,
        "error_message": null
      }
    ]
  }
}

Get one profile

Request

curl "https://api.musimap.com/v1/profiling/profiles/$PROFILE_ID" \
  -H "Authorization: Bearer $ACCESS_TOKEN"

Returns the same data shape as the create response. A profile that does not exist or belongs to another organisation returns HTTP 404.

Errors

  • 400 validation_error: invalid request, for example a missing idempotency_key, a track item without exactly one identifier, an unknown profile family, a missing or inaccessible catalog_id, or an unknown query parameter on the list call.
  • 401: missing or invalid bearer token.
  • 402: insufficient profiling credits.
  • 403: the token lacks profiling.write or profiling.read, or your organisation is not entitled to profiling.
  • 404: profile not found.
  • 422 insufficient_eligible_tracks: fewer than 5 distinct eligible tracks.
  • 429: rate limited.
  • 503: profiling backend temporarily unavailable.

422 insufficient_eligible_tracks

No profile is generated and the credit is refunded. required_count is the minimum; eligible_count is how many distinct eligible tracks were found. Add analysed tracks and retry with a new idempotency_key.

Response

{
  "status": 422,
  "message": "Validation failed.",
  "data": {
    "error_code": "insufficient_eligible_tracks",
    "details": "MusiProfile requires at least 5 distinct analysed tracks; 3 eligible after resolution. Unresolved, duplicate, or untagged tracks do not count.",
    "required_count": 5,
    "eligible_count": 3
  }
}

Envelope shape and shared codes: Errors. Pagination envelope: Pagination.