Skip to content

Tutorial

End-to-end walkthrough of distributing a product through the limbo/Beat API. The flow is:

authenticate → create label → create product → create tracks → create records → assign rights → update & validate the default offer → activate the product → create a DSP-specific offer → create a send task → poll the send task status.

All resource endpoints live under /api/v1 and follow the JSON:API convention (Content-Type: application/vnd.api+json). Replace https://domain.com with your environment host and <token> with the bearer token obtained in the first step.


Authentication

@username = email@email.com
@password = password

POST https://domain.com/oauth/token
Content-Type: application/json

{
    "grant_type": "password",
    "email": "{{username}}",
    "password": "{{password}}"
}

Note: Your distributor ID and company ID are delivered together with your credentials.

See authentication.md.


Create Label

A label must be associated with a company.

@urlBase = https://domain.com/api/v1
@token = <token>

@company = 1

POST {{urlBase}}/labels
Content-Type: application/vnd.api+json
Authorization: Bearer {{token}}

{
    "data": {
        "type": "labels",
        "attributes": {
            "name": "Label name",
            "description": "Label description"
        },
        "relationships": {
            "company": {
                "data": {
                    "type": "companies",
                    "id": "{{company}}"
                }
            }
        }
    }
}

See labels.md.


Create Product

The product must be associated with a label and must declare its product type (Album, Single, etc.) and its language.

@urlBase = https://domain.com/api/v1
@token = <token>

@label = 1
@product_type = 1
@language = 5

POST {{urlBase}}/products
Content-Type: application/vnd.api+json
Authorization: Bearer {{token}}

{
  "data": {
    "type": "products",
    "attributes": {
      "name": "Product title",
      "upc-code": "8088111222333",
      "release-date": "2023-10-01",
      "front-cover": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEA...",
      "copyright-line": "Records Music",
      "production-line": "2023 Records Music",
      "production-year": 2023,
      "status": "draft",
      "artist": [
        "Artist name"
      ]
    },
    "relationships": {
      "product-type": {
        "data": {
          "type": "product-types",
          "id": "{{product_type}}"
        }
      },
      "language": {
        "data": {
          "type": "languages",
          "id": "{{language}}"
        }
      },
      "label": {
        "data": {
          "type": "labels",
          "id": "{{label}}"
        }
      }
    }
  }
}

Important: On creation the product status must be "draft". The product is moved to "active" later, in a separate update (see Validate and update the product). Genre and subgenre are not product attributes — they are set on the offer.

See products.md, labels.md, product-types.md, languages.md.


Create Track

Create as many tracks as the album contains. Every track is associated with a product and declares its audio language.

@urlBase = https://domain.com/api/v1
@token = <token>

@product = 1
@language = 5

POST {{urlBase}}/tracks
Content-Type: application/vnd.api+json
Authorization: Bearer {{token}}

{
    "data": {
        "type": "tracks",
        "attributes": {
            "title": "Track title",
            "track-number": 1,
            "volume-number": 1,
            "isrc-code": "ESA112314511",
            "artist": ["Artist name"]
        },
        "relationships": {
            "product": {
                "data": {
                    "type": "products",
                    "id": "{{product}}"
                }
            },
            "audio-language": {
                "data": {
                    "type": "languages",
                    "id": "{{language}}"
                }
            }
        }
    }
}

See tracks.md, products.md, languages.md.


Create Record

A record holds the FLAC audio file associated with a track (creator). Create as many records as there are tracks associated with the product.

@urlBase = https://domain.com/api/v1
@token = <token>

@track = 1

POST {{urlBase}}/records
Content-Type: application/vnd.api+json
Authorization: Bearer {{token}}

{
    "data": {
        "type": "records",
        "attributes": {
            "new-file": "ZkxhQwAAACISABIAAAAQACNMC7gDcAABN0su1..."
        },
        "relationships": {
            "creator": {
                "data": {
                    "type": "tracks",
                    "id": "{{ track }}"
                }
            }
        }
    }
}

See records.md, tracks.md.


Create Right

Rights are associated with an email, declaring which distributor they belong to, the product, the DSPs, and the territories (either continents or territories).

@urlBase = https://domain.com/api/v1
@token = <token>

@distributor = 1
@product = 1
@dsp = 23
@continent = 1

POST {{urlBase}}/rights
Content-Type: application/vnd.api+json
Authorization: Bearer {{token}}

{
    "data": {
        "type": "rights",
        "attributes": {
            "action": "add",
            "user-email": "user-email@user-email.com"
        },
        "relationships": {
            "distributor": {
                "data": {
                    "type": "distributors",
                    "id": "{{ distributor }}"
                }
            },
            "distributed": {
                "data": {
                    "type": "products",
                    "id": "{{ product }}"
                }
            },
            "dsps": {
                "data": [{
                    "type": "dsps",
                    "id": "{{ dsp }}"
                }]
            },
            "continents": {
                "data": [{
                    "type": "continents",
                    "id": "{{ continent }}"
                }]
            }
        }
    }
}

Note: The product relationship is named distributed (not product). At least one DSP is required.

See products.md, continents.md, territories.md, dsps.md.


Update and validate the default offer

Each product has a default offer. This offer must be updated and validated by changing its status to active.

The default offer requires a release date, genre and subgenre.

Note: The default offer must NOT contain any DSP-related information.

Find the default offer

@urlBase = https://domain.com/api/v1
@token = <token>

@product = 1

GET {{urlBase}}/offers?filter[product-id]={{product}}&filter[is-default]=true
Content-Type: application/vnd.api+json
Authorization: Bearer {{token}}

Look up DistributorProductSubgenres

@urlBase = https://domain.com/api/v1
@token = <token>

GET {{urlBase}}/distributor-product-subgenres
Content-Type: application/vnd.api+json
Authorization: Bearer {{token}}

See distributor-product-subgenres.md.

Update the default offer

Assign a release date, genre and subgenre.

@urlBase = https://domain.com/api/v1
@token = <token>

@default_offer = 1
@subgenre = 1
@subgenre2 = 2

PATCH {{urlBase}}/offers/{{default_offer}}
Content-Type: application/vnd.api+json
Authorization: Bearer {{token}}

{
    "data": {
        "type": "offers",
        "id": "{{ default_offer }}",
        "attributes": {
            "release-date": "2023-10-01"
        },
        "relationships": {
            "subgenre": {
                "data": {
                    "type": "distributor-product-subgenres",
                    "id": "{{ subgenre }}"
                }
            },
            "subgenre2": {
                "data": {
                    "type": "distributor-product-subgenres",
                    "id": "{{ subgenre2 }}"
                }
            }
        }
    }
}

See offers.md, distributor-product-subgenres.md.

Validate the default offer by setting its status to active

If the offer data is complete, it becomes active.

@urlBase = https://domain.com/api/v1
@token = <token>

@default_offer = 1

PATCH {{urlBase}}/offers/{{default_offer}}
Content-Type: application/vnd.api+json
Authorization: Bearer {{token}}

{
    "data": {
        "type": "offers",
        "id": "{{ default_offer }}",
        "attributes": {
            "status": "active"
        }
    }
}

See offers.md.


Validate and update the product

If the product is complete, set its status to active.

@urlBase = https://domain.com/api/v1
@token = <token>

@product = 1

PATCH {{urlBase}}/products/{{product}}
Content-Type: application/vnd.api+json
Authorization: Bearer {{token}}

{
    "data": {
        "type": "products",
        "id": "{{ product }}",
        "attributes": {
            "status": "active"
        }
    }
}

See products.md.


Create a DSP-specific offer

The specific offer is the one that has the DSP(s) you want to distribute the product to associated with it.

Important! The status must be active and you must indicate that it is not a default offer.

status: "active" is-default: false

Look up DspUploadIdentifications

@urlBase = https://domain.com/api/v1
@token = <token>

GET {{urlBase}}/dsp-upload-identifications
Content-Type: application/vnd.api+json
Authorization: Bearer {{token}}

Note: Filter by filter[dsp-id] for reliable results.

See dsp-upload-identifications.md.

Create the offer

@urlBase = https://domain.com/api/v1
@token = <token>

@product = 1
@subgenre = 1
@subgenre2 = 2
@dsp_upload_identification = 1876

POST {{urlBase}}/offers
Content-Type: application/vnd.api+json
Authorization: Bearer {{token}}

{
    "data": {
        "type": "offers",
        "attributes": {
            "release-date": "2023-10-01",
            "is-default": false,
            "status": "active",
            "usage": {
                "download": true,
                "copy_scan": true,
                "on_demand_stream": true,
                "non_interactive_stream": true
            }
        },
        "relationships": {
            "product": {
                "data": {
                    "type": "products",
                    "id": "{{ product }}"
                }
            },
            "subgenre": {
                "data": {
                    "type": "distributor-product-subgenres",
                    "id": "{{subgenre}}"
                }
            },
            "subgenre2": {
                "data": {
                    "type": "distributor-product-subgenres",
                    "id": "{{subgenre2}}"
                }
            },
            "dsp-upload-identifications": {
                "data": [{
                    "type": "dsp-upload-identifications",
                    "id": "{{dsp_upload_identification}}"
                }]
            }
        }
    }
}

Important: A non-default offer set to "active" requires at least one dsp-upload-identifications. If omitted, the request is rejected with a 422.

See offers.md, products.md, distributor-product-subgenres.md, dsp-upload-identifications.md.


Send Task

To deliver to the DSP, create a task indicating the product and which DSP to send it to.

Note: Deliveries to DSPs are performed individually (one task per DSP).

The delivery types are:

delivery (for an initial delivery)
update   (only for a metadata update)
delete   (for a takedown)

Important: The product must already be "active" before creating the send task (except for delete deliveries). When deliverable is true, the delivery starts on creation — there is no separate "trigger" step. You cannot create a second task for the same product + DSP + delivery type while a previous one is still in progress (i.e. not error or completed).

@urlBase = https://domain.com/api/v1
@token = <token>

@product = 1
@dsp_upload_identification = 1876

POST {{urlBase}}/send-tasks
Content-Type: application/vnd.api+json
Authorization: Bearer {{token}}

{
    "data": {
        "type": "send-tasks",
        "attributes": {
            "deliverable": true,
            "delivery-type": "delivery"
        },
        "relationships": {
            "product": {
                "data": {
                    "type": "products",
                    "id": "{{ product }}"
                }
            },
            "dsp-upload-identification": {
                "data": {
                    "type": "dsp-upload-identifications",
                    "id": "{{ dsp_upload_identification }}"
                }
            }
        }
    }
}

See send-tasks.md, products.md, dsp-upload-identifications.md.


Check the task status

@urlBase = https://domain.com/api/v1
@token = <token>

@send_task_id = 1

GET {{urlBase}}/send-tasks/{{send_task_id}}
Content-Type: application/vnd.api+json
Authorization: Bearer {{token}}

Poll this endpoint until the task reaches a terminal state. The status attribute describes progress; ack-status-message carries the acknowledgment payload returned by the DSP.

Send task status values

The platform uses the following values:

status Meaning
pending Initial state — the task has been created but the delivery has not started
waiting Delivery in progress — awaiting the DSP acknowledgment
procesing The delivery is being processed
completed The DSP acknowledged the delivery successfully — terminal success state
error The delivery or acknowledgment failed

A successful delivery ends with status: "completed". A failed one ends with status: "error".

Example response

"attributes": {
      "deliverable": true,
      "delivery-type": "delivery",
      "status": "completed",
      "send-date": "2023-08-14 18:11:51",
      "batch-id": "1ccf3f14-03a1-4001-9218-f7e06c725a13",
      "ack-status-message": {
        "FileStatus": [
          "FileOK"
        ]
      },
      "sent-at": null,
      "packaged-by": null,
      "sent-by": null,
      "message-id": "PADPIDA200010120333312786830",
      "sent-on": "20230814181151288",
      "created-by": "robot",
      "created-at": "2023-08-14T18:11:48.000000Z",
      "updated-at": "2023-08-14T18:12:33.000000Z"
    }

See send-tasks.md.