This tutorial details all the steps involved in putting an album online, from creating a Label to creating a SendTask (i.e., a delivery to a DSP).
Authenticate
First of all, let’s get a token to authenticate against the API.
require "rest-client"
require "json"
login = "Login"
password = "Password"
response = RestClient . post (
"https://api.idol.io/oauth/token" ,
{
grant_type: "password" ,
username: login,
password: password
}
)
token = JSON . parse (response)[ "access_token" ] // => 'c90450...'
Create Label
Each album has to be associated with a Label. Let's create a new Label and name it Demo label .
First, all labels are associated to a Company (called Contract in the Labelcamp UI ). In a standard delivery context, only a single Company is mandatory, to which you can associate all your Labels . We need to retrieve the available companies:
response = RestClient . get (
"https://api.idol.io/api/v2/companies" ,
"Authorization" : "Bearer <token>" ,
"Content-Type" : "application/vnd.api+json"
)
JSON . parse (response)[ 'data' ]
// => [{ "id" => "666" , "type" => "companies" , "links" =>{ "self" => "https://api.idol.io/api/v2/companies/<ID>" }, "attributes" =>{ "created-at" => "2013-11-18T08:07:13.000+01:00" , "updated-at" => "2018-02-21T18:06:19.311+01:00" , "name" => "Record Company" , "children-count" => 6 , "label-manager" => nil , "is-tva-applicable" => true }, "relationships" =>{ "distributor" =>{ "links" =>{ "self" => "https://api.idol.io/api/v2/companies/<ID>/relationships/distributor" , "related" => "https://api.idol.io/api/v2/companies/<ID>/distributor" }, "data" =>{ "type" => "distributors" , "id" => "13" }},
company
The Company demo (id: 666 ) is the one available, we will use it to create our Label :
response = RestClient . post (
"https://api.idol.io/api/v2/labels" ,
{
"data" : {
"attributes" : {
"name" : "My beautiful Label" ,
"cover-url" : '' ,
"usage" : {
"download" : true ,
"copy_scan" : true ,
"on_demand_stream" : true ,
"non_interactive_stream" : true
}
},
"relationships" : {
"rights" : {
"data" : []
},
"company" : {
"data" : {
"type" : "companies" ,
"id" : "<ID>"
}
},
},
"type" : "labels"
}
}. to_json ,
"Content-Type" : 'application/vnd.api+json' ,
"Authorization" : "Bearer #{token} "
)
JSON . parse (response)[ 'data' ]
// => [{ "id" => "555" , "type" => "labels" ...}]
label
Create Product
Now that we have the label (id : 555 ), we can create the Product :
response = RestClient . post (
"https://api.idol.io/api/v2/products" ,
{
"data" : {
"attributes" : {
"artist" : [
"Artist demo"
],
"name" : "Demo album" ,
"is-compilation" : false ,
"upc-code" : "" ,
"copyright-line" : "2025 Demo" ,
"production-line" : "2025 Demo" ,
"production-year" : 2025
},
"relationships" :{
"label" :{
"data" :{
"type" : "labels" ,
"id" : "555"
}
}
},
"type" : "products"
}
}. to_json ,
"Authorization" : "Bearer {token}" ,
"Content-Type" : "application/vnd.api+json"
)
product = JSON . parse (response)[ 'data' ]
// => [{ "id" => "214477" , "type" => "products" ...}]
product
Import Record
Each album contains one or more tracks. Let’s create a Track :
response = RestClient . post (
"https://api.idol.io/api/v2/tracks" ,
{
"data" : {
"attributes" : {
"title" : "My title" ,
"artist" : [
"My Artist"
],
"isrc-code" : "AEA020900003" ,
"track-number" : "3" ,
"volume-number" : "1" ,
},
"relationships" : {
"product" : {
"data" : {
"id" : "214477" ,
"type" : "products"
}
}
},
"type" : "tracks"
}
}. to_json ,
"Authorization" : "Bearer <token>" ,
"Content-Type" : "application/vnd.api+json"
)
track = JSON . parse (response)[ 'data' ]
// => [{ "id" => "1709847" , "type" => "tracks" ...}]
track
Now, you need to associate a FLAC audio file with the Track . To do this, you must create an ImportTask and attach a download link to the record.
The ImportTask will be processed asynchronously and will result in the creation of a new Record attached to the Track.
Here is how to create an ImportTask:
Find more information about audio specifications in this Help Center's article .
response = RestClient . post (
"https://api.idol.io/api/v2/import-tasks" ,
{
"data" : {
"id" : < ID > ,
"type" : "import-tasks" ,
"attributes" : {
"created-at" : "2024-12-22T16:33:38.866+01:00" ,
"updated-at" : "2024-12-22T16:33:38.866+01:00" ,
"precision" : "24" ,
"master-type" : "hd" ,
"status" : "uploaded" ,
"url" : 'https://<download_record_url>' ,
},
"relationships" : {
"attachable" : {
"data" : {
"type" : "tracks" ,
"id" : "<ID>"
}
}
}
}
}. to_json ,
"Authorization" : "Bearer <token>" ,
"Content-Type" : "application/vnd.api+json"
)
import_task = JSON . parse (response)[ 'data' ]
// => [{ "id" => "4372632" , "type" => "import-tasks" ...}]
importtasknew
Add Rights
Our album must only be available on Apple Music and Spotify, with US rights.
We need to retrieve the Territory ID for US :
response = RestClient . get (
"https://api.idol.io/api/v2/territories?filter[code_alpha_2]=US" ,
Authorization: "Bearer <token>" ,
"Content-Type" : 'application/vnd.api+json'
)
JSON . parse (response)[ 'data' ]. first [ 'id' ]
// => "223"
territories
If you haven't read it yet, please read this article on how to manage static resources .
Then we need to retrieve our Distributor ID :
response = RestClient . get (
"https://api.idol.io/api/v2/distributors?filter[name]=Distributeur test" ,
Authorization: "Bearer <token>" ,
"Content-Type" : "application/vnd.api+json"
)
JSON . parse (response)[ 'data' ]. first [ 'id' ]
// => "13"
Distributor
We also need to retrieve the Apple Music and Spotify IDs :
response = RestClient . get (
"https://api.idol.io/api/v2/dsp-upload-identifications?include=dsp" ,
"Content-Type" : 'application/vnd.api+json' ,
"Authorization" : "Bearer <token>"
)
JSON . parse (response)[ 'data' ]
// => [{ "id" => "374" , "type" => "dsp-upload-identifications" , "links" =>{ "self" => "https://api.idol.io/api/v2/dsp-upload-identifications/<ID>" }, "attributes" =>{ "created-at" => "2012-12-13T18:50:17.000+01:00" , "updated-at" => "2018-05-30T11:30:59.837+02:00" , "dsp-name" => "Apple" }, "relationships" =>{ "offers" =>{ "links" =>{ "self" => "https://api.idol.io/api/v2/dsp-upload-identifications/<ID>/relationships/offers" , "related" => "https://api.idol.io/api/v2/dsp-upload-identifications/<ID>/offers" }}, "dsp" =>{ "links" =>{ "self" => "https://api.idol.io/api/v2/dsp-upload-identifications/<ID>/relationships/dsp" , "related" => "https://api.idol.io/api/v2/dsp-upload-identifications/<ID>/dsp" }, "data" =>{ "type" => "dsps" , "id" => "3" }}}}...
dspuploadidentification
Now, we have to set the distribution rules for this album. Let’s add the territories and DSPs information :
response = RestClient . post (
"https://api.idol.io/api/v2/rights" ,
{
"data" : {
"attributes" : {
"action" : "add" ,
"user-email" : "api.test@idol.io"
},
"relationships" : {
"dsps" : {
"data" : [{
"type" : "dsps" ,
"id" : "3"
},
{
"type" : "dsps" ,
"id" : "30"
}]
},
"territories" : {
"data" : [{
"type" : "territories" ,
"id" : "223"
}]
},
"distributor" : {
"data" : {
"type" : "distributors" ,
"id" : "13"
}
},
"distributed" : {
"data" : {
"type" : "products" ,
"id" : "214477"
}
}
},
"type" : "rights"
}
}. to_json ,
"Authorization" : "Bearer <token>" ,
"Content-Type" : "application/vnd.api+json"
)
right
Update and validate default Offer
When you create a product, a default Offer is associated to the Product (this default offer is not associated with any DspUploadIdentification ).
You can retrieve the default Offer like this:
response = RestClient . get (
"https://api.idol.io/api/v2/offers?filter[product_id]=214477&filter[is_default]=true" ,
"Content-Type" : 'application/vnd.api+json' ,
"Authorization" : "Bearer <token>"
)
offer_id = JSON . parse (response)[ 'data' ]. first [ 'id' ]
// => 377099
offer
Then, to retrieve our product and track Price Codes , we use the following request:
RestClient . get (
"https://api.idol.io/api/v2/distributor-price-codes" ,
"Content-Type" : 'application/vnd.api+json' ,
"Authorization" : "Bearer <token>"
)
distributorpricecode
In this example, we will use the product Price Code ID 10 and track Price Code ID 7 .
Now, we use this request to retrieve the product's genre:
RestClient . get (
"https://api.idol.io/api/v2/distributor-product-subgenres" ,
"Content-Type" : 'application/vnd.api+json' ,
"Authorization" : "Bearer <token>"
)
distributorproductsubgenres
In this example, we will use the Product Genre ID 1 .
Then, we must validate the default Offer :
response = RestClient . put (
"https://api.idol.io/api/v2/offers/<ID>" ,
{
"data" : {
"id" : "377099" ,
"attributes" : {
"status" : "active" ,
"release-date" : "2025-01-01" ,
"is-default" : true
},
"relationships" : {
"price-code" : {
"data" : {
"type" : "distributor-price-codes" ,
"id" : "10"
}
},
"track-price-code" : {
"data" : {
"type" : "distributor-price-codes" ,
"id" : "7"
}
},
"subgenre" : {
"data" : {
"type" : "distributor-product-subgenres" ,
"id" : "1"
}
},
"product" :{
"data" :{
"type" : "products" ,
"id" : "214477"
}
}
},
"type" : "offers"
}
}. to_json ,
"Content-Type" : 'application/vnd.api+json' ,
"Authorization" : "Bearer <token>"
)
offer
Create specific Apple Music / iTunes Offer
You may want to create a specific Offer for Apple Music / iTunes , for example, to set a specific pre-order date:
response = RestClient . post (
"https://api.idol.io/api/v2/offers" ,
{
"data" : {
"attributes" : {
"status" : "active" ,
"preorder-date" : "2024-05-01T00:00:00.000+00:00" ,
"release-date" : "2025-01-01" ,
"is-default" : false
},
"relationships" : {
"product" : {
"data" : {
"type" : "products" ,
"id" : "214477"
}
},
"dsp-upload-identifications" : {
"data" : [{
"type" : "dsp-upload-identifications" ,
"id" : "374"
}]
}
},
"type" : "offers"
}
}. to_json ,
"Content-Type" : 'application/vnd.api+json' ,
"Authorization" : "Bearer <token>"
)
itunes_offer_id = JSON . parse (response)[ 'data' ][ 'id' ]
// => 377752
Update and validate the Product
Before you can send deliveries to DSPs, a product must be updated and validated . To achieve this, the product status should be changed to 'active' :
response = RestClient . put (
"https://api.idol.io/api/v2/products/214477" ,
{
"data" : {
"id" : "214477" ,
"attributes" : {
"status" : "active"
},
"type" : "products"
}
}. to_json ,
"Content-Type" : 'application/vnd.api+json' ,
"Authorization" : "Bearer <token>"
)
status = JSON . parse (response)[ 'data' ][ 'attributes' ][ 'status' ]
// => "active"
product
The total weight of a product - masters and visual assets included - should not exceed 50gb to guarantee deliverability
Create DSP Artist IDs
Setting the album to an 'active' status automatically creates Artists entities, which are linked to the Product through its associated Roles . More information on this process here .
You're now able to create platform-specific artist IDs, if and when required, e.g. a Spotify Artist URI or an Apple Artist ID.
First, we need to retrieve the artist linked to our Product:
response = RestClient . get (
"https://api.idol.io/api/v2/artists?filter[product_id]=214477
" Content - Type ": 'application/vnd.api+json',
" Authorization ": " Bearer < token > "
)
puts JSON.parse(response)['data']
// => [{ " id ": " 82372 ", " type ": " artists ", " links ": { " self ": " https: // l - api. idol . io / api / v2 / artists / 1495354 " }, " attributes ": { " name ": " Artist demo ", " priority ": 1 }}]}...
artist_id = JSON.parse(response)['data'].first['id']
// => 82372
Now that we've retrieved the artist, we'll create an artist ID for Spotify :
response = RestClient . post (
"https://api.idol.io/api/v2/availabilities" ,
{
"data" :{
"attributes" :{
"external" :"spotify:artist:4XGbuIJBheaKE2UGZ33am9"
},
"relationships" :{
"dsp" :{
"data" :{
"type" :"dsps" ,
"id" :"30"
}
},
"item" :{
"data" :{
"type" :"artists" ,
"id" :"3163837"
}
}
},
"type" :"availabilities"
}
}. to_json ,
"Content-Type" : 'application/vnd.api+json' ,
"Authorization" : "Bearer <token>"
)
And, for Apple :
response = RestClient . post (
"https://api.idol.io/api/v2/availabilities" ,
{
"data" :{
"attributes" :{
"external" :"1798210185"
},
"relationships" :{
"dsp" :{
"data" :{
"type" :"dsps" ,
"id" :"3"
}
},
"item" :{
"data" :{
"type" :"artists" ,
"id" :"3163837"
}
}
},
"type" :"availabilities"
}
}. to_json ,
"Content-Type" : 'application/vnd.api+json' ,
"Authorization" : "Bearer <token>"
)
Note that DSPs like Apple and Spotify provide APIs to directly create and/or retrieve existing Artist IDs from their databases.
Deliver to Apple and Spotify
Finally, we must create a SendTask (called a 'Delivery' in our UI) to Apple Music for this album. Setting the deliverable attribute to 'true' will allow the system to enqueue its delivery to Apple:
response = RestClient . post (
"https://api.idol.io/api/v2/send-tasks" ,
{
"data" : {
"attributes" : {
"deliverable" : "true" ,
"delivery-type" : "delivery" ,
"priority" : "normal"
},
"relationships" : {
"product" : {
"data" : {
"type" : "products" ,
"id" : "214477"
}
},
"dsp-upload-identification" : {
"data" : {
"type" : "dsp-upload-identifications" ,
"id" : "374"
}
}
},
"type" : "send-tasks"
}
}. to_json ,
"Content-Type" : 'application/vnd.api+json' ,
"Authorization" : "Bearer <token>"
)
send_task_id = JSON . parse (response)[ 'data' ][id]
// => 7434479
We'll do the same for Spotify :
response = RestClient . post (
"https://api.idol.io/api/v2/send-tasks" ,
{
"data" : {
"attributes" : {
"deliverable" : "true" ,
"delivery-type" : "delivery" ,
"priority" : "normal"
},
"relationships" : {
"product" : {
"data" : {
"type" : "products" ,
"id" : "214477"
}
},
"dsp-upload-identification" : {
"data" : {
"type" : "dsp-upload-identifications" ,
"id" : "375"
}
}
},
"type" : "send-tasks"
}
}. to_json ,
"Content-Type" : 'application/vnd.api+json' ,
"Authorization" : "Bearer <token>"
)
send_task_id = JSON . parse (response)[ 'data' ][id]
// => 7434480
send-task
:rocket: And your album is now ready to be delivered to Apple Music & Spotify, with US territory rights and a specific pre-order date on Apple Music / iTunes .
Webhooks
To follow the status of your send_tasks, you can create a Webhook:
response = RestClient . post (
"https://api.idol.io/api/v2/webhooks" ,
{
"data" : {
"attributes" : {
"action" : "send_task_status_update" ,
"url" : "https://yourdomain.com/callbacks?id=<id>&value=<value>&updated_at=<time>"
},
"relationships" : {
"distributor" : {
"data" : {
"type" : "distributors" ,
"id" : "13"
}
}
},
"type" : "webhooks"
}
}. to_json ,
"Content-Type" : 'application/vnd.api+json' ,
"Authorization" : "Bearer <token>"
)
We will then trigger an HTTP call on the URL:
POST https: //yourdomain.com/callbacks
{
"id" : "1" ,
"value" : "1" ,
"time" : "2022-09-12 00:00:00" ,
"kind" : "action"
}
webhooks
Last modified on January 21, 2026