Partner Integration & Web API Documentation

Getting Started


Integrating with Loudr

Partners integrating with Loudr may choose to deliver license requests (or simply, requests):

The Loudr Web API has the advantage of providing realtime access to the status of license requests, including fulfillment status, underlying work metadata, etc.

  • Loudr Web API Access:

    • To gain access to the Loudr Web API, partners will need complete the all 4 steps of the integration roadmap.
  • Manual Access:

    • Partners choosing to deliver their requests manually will need to complete steps 1 and 3 of the integration roadmap and be able to create a bulk request delivery file and usage report file.


Integration Roadmap

Integrating with Loudr is made simple by following the Integration Roadmap. The Roadmap consists of 3 tests that will verify everything is working smoothly for both parties.

Test 1 - Content Match & Formatting

This test is designed to provide feedback on incoming requests - both in terms of content and formatting. We ask integrating partners to provide us a sample set of sound recordings in order to satisfy data formatting & coverage quality assurance.

Test 1:

  1. Deliver sample set of sound recordings in chosen format

  2. Loudr will verify data formatting.

  3. Partner will be approved to send sound recordings to Loudr and will be given a test access token for integrating with Loudr Web API.

Test 2 - Request Integration & Data Exchange

For partners not integrating directly with the API, this test is optional.

This test is required for partners integrating with Loudr Web API to ensure everything is working as expected. You will only be granted an access token if this test is complete.

Test 2:

  1. Deliver at least 9 correctly formatted requests with a “sandbox” access secret provided by Loudr.

    • You may contact your business representative to obtain a “sandbox” access secret if you do not already have one.
  2. Upon successful delivery, Loudr will provide responses.

    • Responses will simulate the following outcomes, and respond with the quoted license statuses:
    • Public Domain (public-domain)
    • Soft Rejection (rejected)
    • Rejection with Notes (rejected-more-info)
    • Hard Rejection (rejected-hard)
    • Archived (archived)
    • Fulfilled via Physical NOI (physical)
    • Fulfilled via Digital NOI (digital)
    • Fulfilled via Direct License (direct)
    • Fulfilled via Blanket License (blanket)
    • Medley fulfillment (medley)
    • Note: For most partners, there may be no functional difference between the methods of fulfillment, as provided by the simulations of physical, digital, direct, and blanket.

Test 3 - Usage Report Integration & Data Exchange

All partners must be able to deliver usage reports according to Loudr’s usage report specification. Loudr asks to receive an example delivery before accepting payments for publisher royalties.

Test 3:

  1. Deliver to Loudr an example usage report using Loudr’s usage report specification.
  2. Loudr will verify formatting and content.
  3. Partner will be approved to send payments for publisher royalties.

Deploying on Production

For partners not integrating directly with the API, this step is optional.

When you deliver requests with your production access token, requests will be actively matched and fulfilled. Congratulations - you’ve integrated with Loudr!

How to deploy:

  1. Complete tests 1, 2, and 3 if you haven’t already.
  2. Loudr will send you a production access token.
  3. Begin sending sound recordings to Loudr production for matching and fulfillment.


Loudr Web API


What is the Web API?

Loudr provides a RESTful API, available via HTTP, to allow partners to integrate their solutions deeply with Loudr.

All API requests require an access token called a “secret,” and the ability to create and parse JSON objects.

Note about examples: All of the following code examples are provided in python, assuming access to the requests library. We believe this framework to be straightforward and that experienced developers will have no trouble understanding the logic.


Authentication via Access Token

Authenticate your account when making requests by providing your access token within the request. Your access token must be provided in the query string argument secret with every HTTP request.

Need an access token?

A test access token is granted upon completion of the first step of the integration roadmap.

Contact Loudr to learn more about our services, and gain access to our Web API.


License Requests

Loudr organizes license requests, within the sound recording that embodies them. This is partly because recordings of medleys must be licensed in whole before the recording is considered cleared for release.

4 Parts of Sound Recordings

  • recording metadata (title, artist, isrc, upc, etc.) - includes recording vendor_id.
  • request metadata (composition title, composer, author, etc.)
  • licensing configuration (e.g. 10 digital download units, 100 physical units)
  • licensing territories (always “United States”)

The Vendor ID

Each set of recordings and requests will be uniquely identified by the partner-provided vendor_id.

Choose a vendor_id that is unique for the recording, configuration, and territories you are requesting the license in. For most partners, it is OK to use the ISRC as the vendor_id, assuming that each ISRC will only be licensed once by Loudr.

Request Formatting


Creating new License Requests

Building the API Payload

The API payload for a new request contains each of the 4 required objects, and may be further studied in Objects - Sound Recordings & License Requests for delivery.

Example: The following code block builds a license request for a recording called “The Legendary Blade”, and asks for permission to deliver infinite DPDs in the United States.

payload = {
    "recording": {
        "album": "Hero of Time",
        "artist": "Eric Buchholz",
        "isrc": "QZ6K41600179",
        "length": 209,
        "release_date": "2017-03-09",
        "title": "The Legendary Blade",
        "label": "Materia Collective",
        "vendor_id": "QZ6K41600179-dpd"
    },
    "requests": [{
        "composer": "Koji Kando",
        "source": "The Legend of Zelda: Ocarina of Time",
        "title": "Temple of Time"
    }],
    "license_territories": ["US"],
    "license_config": {
        "dpd": -1
    }
}

Sending the Request

The request is sent by delivering a PUT HTTP request to /api/client/sound_recording.

response = requests.put("https://loudr.fm/api/client/sound_recording?secret="+SECRET,
    json.dumps(payload),
    headers={"content_type":"application/json"})
assert response.status_code == 201, "Loudr returned status %d;\n%s" % (response.status_code, response.content)  # new content == 201

The payload expects a Sound Recording Object.

Parsing the Response

The response will be the Sound Recording API object, which will include a thorough breakdown of the license status.

Creating a new recording yields status 201, while saving an existing recording yields status 200.

The response will include these important properties:

  • license_status - Status of the requests.
  • license_fulfilled_at - Timestamp at which the request was considered fulfilled.
  • earliest_clearance_at - If provided, this is the earliest timestamp at which this content may be released.
  • rel.canonical - API URI to access this sound recording directly. Performing a GET to this URI will fetch the latest information about this recording. Performing a POST to this URI will update the request and recording metadata, if such an operation is allowed.
  • requests - Each request is represented as an object inside of requests. Included are two meta objects:

    • provided_research describes provided research metadata.
    • composition_index is a relational index for the request within the sound recording. This is required when updating the request.
  • See Sound Recording API Object in Responses for more details.

Sound Recording Object Response:

{
  "client": "creator/Kadqr",
  "license_requested_at": "2017-03-09T00:00:00",
  "updated_at": "2017-03-09T00:00:00",
  "earliest_clearance_at": null,
  "fulfillment": null,
  "fulfillment_status": {
    "allowed_expense": {
      "name": "NONE",
      "value": 0
    },
    "license_fulfilled": false,
    "license_fulfilled_at": null,
    "maximum_expense": 0
  },
  "is_hard_rejection": false,
  "is_public_domain": false,
  "is_rejection": false,
  "license_config": {
    "dpd": -1
  },
  "license_fulfilled_at": null,
  "license_kind": "client request",
  "license_status": 2,
  "license_status_str": "In Progress",
  "licensor": null,
  "matched_compositions": [],
  "payment_complete": false,
  "payment_initiated": null,
  "recording": {
    "album": "Hero of Time",
    "artist": [
      "Eric Buchholz"
    ],
    "isrc": "QZ6K41600179",
    "label": "Materia Collective",
    "length": 209,
    "licensor": null,
    "release_date": "2017-03-09T00:00:00",
    "title": "The Legendary Blade",
    "upc": null,
    "vendor_album_id": null,
    "vendor_id": "QZ6K41600179-dpd"
  },
  "rejections": [],
  "rel": {
    "canonical": "/api/client/sound_recording/Kadqr/QZ6K41600179-dpd"
  },
  "renewal_complete": null,
  "renewal_failed": null,
  "renewal_of": null,
  "requests": [
    {
      "expense": {
        "name": "NONE",
        "value": 0
      },
      "provided_research": {
        "album": [],
        "artist": [],
        "author": [],
        "composer": [
          "Koji Kando"
        ],
        "composition_index": 0,
        "iswc": null,
        "link": [],
        "notes": null,
        "source": [
          "The Legend of Zelda: Ocarina of Time"
        ],
        "suggested_composition": "",
        "title": [
          "Temple of Time"
        ]
      }
    }
  ],
  "royalty_rates": {
    "dpd": "0.091"
  },
  "uri": "sound_recording/creator/Kadqr--QZ6K41600179-dpd"
}


Rejected License Requests

In certain circumstances, Loudr may reject a request.

There are two types of rejections:

  • A soft rejection occurs when re-submitting a request is expected.
  • A hard rejection occurs when a request is not licensable, and can not be resubmitted.

Determining if a request has been rejected

# The same URI may be built with just the vendor_id and client_id.
# "/api/client/sound_recording/%s/%s?secret=%s" % (client_id, vendor_id, secret)
sound_recording_canonical = "https://loudr.fm"+sound_recording['rel']['canonical']
response = requests.get(sound_recording_canonical+"?secret="+SECRET)
sound_recording = response.json()
is_rejected = sound_recording["is_rejection"]
is_hard_rejection = sound_recording["is_hard_rejection"]

Rejection metadata lives in response["rejections"], as a list of all outstanding rejections.

"rejections": [{
  "reason": "This recording contains a non-musical work, and is not eligible for licensing. Please do NOT re-submit this work.",
  "reason_id": 6,
  "notes": "Notes specific to this rejection MAY appear here.",
  "is_hard_rejection": true,
  "composition_index": 0
}]

Typical reasons for a request rejection:

  • Provided composition information is insufficient to identify the underlying musical work(s). Please re-submit with additional identifying information. [soft]
  • Provided composition information is improperly formatted (for example, multiple pieces of information in the same field). Please reformat the provided information and re-submit. [soft]
  • This musical work has been pre-emptively blocked by a publisher, and cannot be released. Please do NOT re-submit this work. [hard]
  • This musical work has not yet been officially released as a phonorecord in the United States. Please re-submit when the work has been officially released. [soft]
  • This recording contains a non-musical work, and is not eligible for licensing. Please do NOT re-submit this work. [hard]

Read on to learn how to [update rejected requests(#updating-rejected-requests).

Updating Rejected Requests

Rejected requests may be updated by making a POST request to the recording’s canonical URI.

  1. Building the Update Payload

    The payload for an update only requires data which has changed.

    payload = {
        "recording": {
            "title": "The Legendary Blades",  # change title to The Legendary Blades
        },
        "requests": [{
            "composer": ["Koji Kando", "Nobuo Uematsu"],  # add composer Nobuo Uematsu
            "composition_index": sound_recording["requests"][0]["provided_research"]["composition_index"]
        }]
    }
    

    In the above example, we have made the recording title plural, and updated the list of composers on the first request to include Nobuo Uematsu.

  2. Sending the Update

    Update the request with a POST to the canonical URI for the recording.

    # Update a recording by sending a POST request to the recordings canonical link.
    sound_recording_canonical = "https://loudr.fm"+sound_recording['rel']['canonical']
    response = requests.post(sound_recording_canonical+"?secret="+SECRET,
        json.dumps(payload),
        headers={"content_type":"application/json"})
    assert response.status_code == 200, "Loudr returned status %d;\n%s" % (response.status_code, response.content)  # saving existing content == 200
    sound_recording = response.json()
    

    Once the update is complete, licensing will be re-attempted.


Querying Multiple Requests

Partners may stay in sync with Loudr’s changes by querying requests that change over time. In most cases, you will not wish to fetch each request separately.

Loudr provides the GET endpoint /api/client/sound_recordings to allow partners to access their sound recordings and requests via access token.

The query response includes:

- rel.next_page - If another “page” of results exists, use this relative API URI to fetch the next page. As long as the response returns a next page, assume that more results exist.

- total - Estimated total number of results.

- results - A list of sound recording objects.

Querying ALL Sound Recordings via Web API

# Query for recordings.
# You may fetch your recordings using /api/client/sound_recordings?secret=<secret>.
response = requests.get("https://loudr.fm/api/client/sound_recordings?secret="+SECRET)

# A page of results will be returned, and may be scrolled using the following logic.
assert response.status_code == 200, "Loudr returned status %d;\n%s" % (response.status_code, response.content)

data = response.json()
total_results = data['total']
sound_recordings = data['results']
next_page = data['rel']['next_page']

# Scroll to the next page.
while next_page:
    # Query for the next page using data['rel']['next_page']
    response = requests.get(LOUDR_BASE+next_page)
    # The next page of results will be returned.
    assert response.status_code == 200, "Loudr returned status %d;\n%s" % (response.status_code, response.content)
    data = response.json()
    # Empty page will signify end of results.
    if not data['results']:
        break
    sound_recordings.extend(data['results'])
    next_page = data['rel']['next_page']

# Assert that our original sound_recording appears in the search.
assert sound_recording_uri in [sr['uri'] for sr in sound_recordings], \
    "Could not find new sound_recording `%s` when querying for recordings." % sound_recording_uri

Querying only Requests which have Changed

Loudr recommends only fetching requests which have changed since you last queried Loudr’s system, This is especially desirable if you have a large number of requests in our system.

To achieve this, use the since query string argument to provide an ISO datestring or unix timestamp (integer of milliseconds) to filter only results which have changed since that time.

since_ms = 1506026411879  # `since` expects timestamp in milliseconds
response = self.api.get("/api/client/sound_recordings", {"secret": SECRET, "since": sice_ms})

Sample API Response

{
  "rel": {
    "next_page": "/api/client/sound_recordings?cursor=DXF1ZXJ5QW5kRmV0Y2gBAAAAAAAAADwWa2FjaGttWjRSeWkyQzhLczdVel9rUQ%3D%3D&secret=..."
  },
  "results": [
    {
      "client": "creator/Kadqr",
      "license_requested_at": "2017-03-09T00:00:00",
      "updated_at": "2017-03-09T00:00:00",
      "earliest_clearance_at": null,
      "fulfillment": null,
      "fulfillment_status": {
        "allowed_expense": {
          "name": "NONE",
          "value": 0
        },
        "license_fulfilled": false,
        "license_fulfilled_at": null,
        "maximum_expense": 0
      },
      "is_hard_rejection": false,
      "is_public_domain": false,
      "is_rejection": false,
      "license_config": {
        "dpd": -1
      },
      "license_fulfilled_at": null,
      "license_kind": "client request",
      "license_status": 2,
      "license_status_str": "In Progress",
      "licensor": null,
      "matched_compositions": [],
      "payment_complete": false,
      "payment_initiated": null,
      "recording": {
        "album": "Hero of Time",
        "artist": [
          "Eric Buchholz"
        ],
        "isrc": "QZ6K41600179",
        "label": "Materia Collective",
        "length": 209,
        "licensor": null,
        "release_date": "2017-03-09T00:00:00",
        "title": "The Legendary Blade",
        "upc": null,
        "vendor_album_id": null,
        "vendor_id": "QZ6K41600179-dpd"
      },
      "rejections": [],
      "rel": {
        "canonical": "/api/client/sound_recording/Kadqr/QZ6K41600179-dpd"
      },
      "renewal_complete": null,
      "renewal_failed": null,
      "renewal_of": null,
      "requests": [
        {
          "expense": {
            "name": "NONE",
            "value": 0
          },
          "provided_research": {
            "album": [],
            "artist": [],
            "author": [],
            "composer": [
              "Koji Kando"
            ],
            "composition_index": 0,
            "iswc": null,
            "link": [],
            "notes": null,
            "source": [
              "The Legend of Zelda: Ocarina of Time"
            ],
            "suggested_composition": "",
            "title": [
              "Temple of Time"
            ]
          }
        }
      ],
      "royalty_rates": {
        "dpd": "0.091"
      },
      "uri": "sound_recording/creator/Kadqr--QZ6K41600179-dpd"
    }
  ],
  "total": 1
}


Sample Python Script

A sample Python script exists to help you dive right in. The application showcases creating a request, querying a request, and updating that request.

See loudr/api-specs/demo_app.py on our github.


Object Schemas

Use these object schemas to augment your understanding of the Web API’s resources.

Sound Recordings & License Requests for delivery

Recording Metadata

Each Sound Recording represents and contains a single recording. The required and optional properties for a recording are as follows:

Properties:

  • title:
    • Recording title.
    • All recordings must have a title.
  • artist:
    • Performing artists on this recording.
    • All recordings must have a performing artist.
  • album:
    • Album this recording appears on.
    • Separate instances of a recording upon multiple releases/albums should be requested as explicitly different sound recordings.
  • isrc:
    • Recording ISRC.
  • upc:
    • UPC for this release.
    • Separate instances of a recording upon multiple releases/albums should be requested as explicitly different sound recordings.
  • label:
    • Label for this release.
  • licensor:
    • Licensing party requesting this release.
  • vendor_id:
    • The vendor id will uniquely identify your requests.
    • When submitting requests for the first time, choose a vendor id which uniquely identifies your records. The recording vendor id is used to identify the recording in usage reports as well as track the license status via the API. You will find the vendor_id on your billing reports, as well.
  • vendor_album_id:
    • Partner's ID for this request's album/release.
    • Similar to the vendor_id, this optional argument is useful when storing relationships between your database and Loudr's.
    • This ID is exposed on Loudr billing reports.
  • release_date:
    • The release date for this recording. This may be used when securing licenses with Loudr's partners. This will be in the format of YYYY-MM-DD.
  • length:
    • The length of this recording in total seconds.
    • All recordings must have a length.

Sample recording metadata:

"recording": {
  "album": "Hero of Time",
  "artist": "Eric Buchholz",
  "isrc": "QZ6K41600179",
  "length": 209,
  "release_date": "2017-03-09",
  "title": "The Legendary Blade",
  "label": "Materia Collective",
  "vendor_id": "QZ6K41600179-dpd"
}

Request Metadata

Each request within a Sound Recording corresponds to one of the recording’s underlying compositions.

Properties:

  • composition_index:

    • Index of this request on an existing sound recording resource.
    • This index is created when submitting new requests for the first time.
  • title:

    • List of known titles for this composition.
    • Requests should contain at least one known title.
  • artist:

    • List of known artists who have performed this composition.
    • May include other popular artists, other than those identified on requested sound recording.
  • composer:

    • List of known composers for this work.
    • Composers and authors may overlap. Composers are typically associated with musical and song authorship.
    • Requests should contain at least one author, or one composer.
  • author:

    • List of known authors for this work.
    • Composers and authors may overlap. Authors are typically associated with lyrical text authorship.
    • Requests should contain at least one author, or one composer.
  • album:

    • List of any other known albums on which this work may appear.
  • source:

    • List of known sources. This may be films, video games, over-arching work compilations, etc.

Requests appear below in JSON as a list of underlying works.

"requests": [
 {
  "composer": "Koji Kando",
  "source": "The Legend of Zelda: Ocarina of Time",
  "title": "Temple of Time"
 }
]

Licensing Territories

Licensing territories describes where fulfillment is sought for each recording. It is a list of ISO-3166 2-digit country codes.

Presently this is always the United States, and no other option is valid. As such, this argument is optional.

JSON example for listing 2-digit

"licensing_territories": ["US"]

Licensing Configuration

The licensing configuration describes the release mediums, and number of distributed units for the recording.

Release mediums:

  • dpd or download - Digital Download
  • stream - Interactive Stream
  • physical - Physical Medium
  • ringtone - Ringtone

Distributed units:

  • Fixed quantity:
    • A simple configuration example of fixed quantities is:
    • 27 digital downloads, 18 interactive streams, 1000 physical copies.
  • Infinite quantities:
    • Most partners will secure licenses for infinite quantities with no requirement for up-front units.
    • infinite (-1) interactive streams, infinite (-1) digital downloads.

The licensing configuration is a map of configurations to units. JSON for infinite quantities of digital downloads and interactive streams:

{
    "dpd": -1,
    "stream": -1
}

-1 units corresponds to infinite units

Previously Licensed Requests?

Send recordings which have previously been recording with a previous_license object.

This will contain the properties:

  • license_id:

    str. Previous license ID from other partner. Required.

  • partner:

    str. Name of previous partner that fulfilled this request. Required. Please ask us what code to use for your previous partner.

  • publisher_ids:

    list:str. List of previous publisher IDs you worked with. This may have been provided by your previous licensing authority.

Example:

"previous_license": {
  "license_id": "123456789",
  "partner": "Licensing Agent",
  "publisher_ids": ["P1234"]
}


Sound Recordings & License Requests in responses

API responses for sound recordings include the basic metadata properties provided by the client: recording, requests, licensing_config, and licensing_territories.

In addition to the metadata, the request’s state, fulfillment status, and matched compositions are also available via the API.

Properties:

  • client:

    str. Request’s partner ID.

  • earliest_clearance_at:

    timestamp. Time when this request may be distributed.

    A license request may be cleared for distribution at a date after the license_fulfilled_at timestamp. If this is the case, earliest_clearance_at returns a timestamp indicating when the release may go live. A null value indicates that there is no additional release restriction.

  • fulfillment:

    object:fulfillment.

    Returns an object containing information about the pending fulfillment for this request.

    Fulfillment Properties:

    • completed: bool. True when the fulfillment is complete.

    • fulfilling_publishers: list:str. Names of fulfilling publishers.

    • fulfillment_license_ids: list:int. Integer IDs which correlate to this specific fulfillment instance. Use this to reference previous fulfillments for your content. These IDs may change if a fulfillment is for any reason re-attempted.

    • fulfillment_methods: list:str. Method used to fulfill this request. May include:

      • blanket
      • digital-noi
      • physical-noi
      • copyright-noi
      • direct
    • territories: list:str. List of ISO-3166 country codes which this fulfillment is valid in.

    • uri: str. The unique URI for this fulfillment.

  • fulfillment_status:

    object:fulfillment-status.

    Details of in-progress fulfillments, or fulfillments which are blocked due to physical expenses. This occurs based on your agreement with Loudr.

    Fulfillment Status Properties:

    • allowed_expense: object:expense. Reserved.
    • license_fulfilled: bool. True when the fulfillment is complete.
    • license_fulfilled_at: timestamp. Timestamp when this license was fulfilled.
    • maximum_expense: int. Reserved.
  • is_hard_rejection:

    bool. True when the request is rejected and the request is not eligible to be re-submitted.

  • is_public_domain:

    bool. True if the request is considered to be licensable via the public domain record.

  • is_rejection:

    bool. True when the request is rejected.

    Rejected requests may be resubmitted via the API.

  • license_config:

    object:license-config.

    See licensing configuration.

  • license_fulfilled_at:

    timestamp. When this license was fulfilled.

  • license_kind:

    str. Expect “client_request”.

  • license_status:

    int. License status.

    Expect one of these status integers depending on your deal with Loudr.

    • 0: Unpaid Payment has not yet been received and this request will not be processed.

    • 1: Payment Pending Payment is pending for this request, and upon completion, processing will occur.

    • 2: In Progress Loudr is attempting to link and fulfill this request.

    • 3: Completed Loudr has secured the appropriate licenses for this request.

    • 4: Rejected Loudr has rejected this request. Please see Rejected License Requests.

    • 5: Pending Expense This request is linked, but cannot be fulfilled due to an expense yielding action which has been blocked due to contract parameters.

    • 6: Archived This request is archived, meaning that it is no longer creating activity.

    • 7: Client Fulfillment This request should be fulfilled via the client's deals with rights holders.

    This and other enumerations are presented on our github @ enums.md.

  • license_status_str:

    str. A string description of the license_status value.

  • licensor:

    str. Name of licensor on the content.

  • matched_compositions:

    list:object:composition. List of compositions matched.

    Compositions returned in this list will include an additional property composition_index corresponding to the composition_index in the provided_research property. See the composition object schema.

  • recording:

    object:recording. Recording metadata, including title, album, etc.

    See recording metadata for delivery.

  • rejections:

    list:object:rejection. List of outstanding rejections for this content. See rejected license requests.

  • rel:

    object:relatives. Contains relative API links related to the request. Expect rel.canonical which points to the API for this request.

  • requests:

    list:object:requests. List of requests on this recording.

    Each request is considered an underlying work for which a license will be obtained.

    Request Object Properties:

    • expense: object:expense. Reserved.

    • provided_research: object:research. Provided information about the underlying work.

      This matches the base request object from the delivery.

  • royalty_rates:

    object:rates. Anticipated per-unit royalty rate for configurations on this request. This decimal will be of variable precision.

  • uri:

    str. Loudr’s unique identifier for this request.

Sample Fulfilled Request from API:

{
  "client": "creator/aBcDeF",
  "earliest_clearance_at": null,
  "fulfillment": {
    "completed": true,
    "fulfilling_publishers": [
      "Bumbly Bee Publishing Co."
    ],
    "fulfillment_license_ids": [
      5871414133915648
    ],
    "fulfillment_methods": [
      "digital-noi"
    ],
    "territories": [
      "US"
    ],
    "uri": "sound_recording/creator/aBcDeF--32917/license_usage/active"
  },
  "fulfillment_status": {
    "allowed_expense": {
      "name": "NONE",
      "value": 0
    },
    "license_fulfilled": true,
    "license_fulfilled_at": "2017-05-31T00:17:52.816830+00:00",
    "maximum_expense": 0
  },
  "is_hard_rejection": false,
  "is_public_domain": false,
  "is_rejection": true,
  "license_config": {
    "dpd": -1
  },
  "license_fulfilled_at": "2017-05-31T00:17:52.816830+00:00",
  "license_kind": "client request",
  "license_status": 3,
  "license_status_str": "Completed",
  "licensor": "The Greatest Bits",
  "matched_compositions": [
    {
      "alias": [],
      "author_names": [
        "Koji Kondo"
      ],
      "author_publisher_pairs": [
        {
          "author": "Koji Kondo",
          "publisher": "Bumbly Bee Publishing Co."
        }
      ],
      "authors": [
        {
          "ipi": null,
          "name": "Koji Kondo",
          "role": {
            "code": "CA",
            "id": 1,
            "name": "Composer & Author"
          }
        }
      ],
      "composition_index": 0,
      "display_name": "Super Mario World Title Theme",
      "id": "abc",
      "kind": "composition",
      "publishers": [
        "Bumbly Bee Publishing Co."
      ],
      "rel": {
        "canonical": "/api/composition/abc"
      },
      "title": "Super Mario World Title Theme",
      "uri": "composition/abc"
    }
  ],
  "recording": {
    "album": "Super Mario World",
    "artist": [
      "The Greatest Bits"
    ],
    "isrc": "QZ22B1800530",
    "label": "The Greatest Bits",
    "length": 125,
    "licensor": "The Greatest Bits",
    "release_date": null,
    "title": "Super Mario World Theme",
    "upc": "1827849330469",
    "vendor_album_id": null,
    "vendor_id": "32917"
  },
  "rejections": [],
  "rel": {
    "canonical": "/api/client/sound_recording/aBcDeF/32917"
  },
  "renewal_complete": null,
  "renewal_failed": null,
  "renewal_of": null,
  "requests": [
    {
      "expense": {
        "name": "NONE",
        "value": 0
      },
      "provided_research": {
        "album": [],
        "artist": [
          "Koji Kondo"
        ],
        "author": [
          "Koji Kondo"
        ],
        "composer": [
          "Koji Kondo"
        ],
        "composition_index": 0,
        "iswc": null,
        "source": [
          "Super Mario World"
        ],
        "suggested_composition": "",
        "title": [
          "Super Mario World Title Theme"
        ]
      }
    }
  ],
  "royalty_rates": {
    "dpd": "0.091"
  },
  "uri": "sound_recording/creator/aBcDeF--32917"
}


Compositions in responses

Compositions are returned as part of the response object, or when requesting an individual composition resource from the API.

Properties:

  • alias:

    list:str. List of potential aliases for this composition.

  • author_names:

    list:str. List of author names that appear on this composition.

  • authors:

    list:object:author. List of author objects which further describe author role and identity. Author Properties:

    • ipi: str. Interested Party Identifier.
    • name: str. Name of author.
    • role: object:role. Role of author.

      Role properties include name for a description of the role and code, and id for a programmable value.

  • composition_index:

    int. Provided only when returned with sound recordings, this property relates to the corresponding request in the requests object.

  • display_name:

    str. A “cleaned up” version of the composition title for displays.

  • id:

    str. Composition ID.

  • kind:

    str. Expect composition.

  • publishers:

    list:str. List of publisher names representing this composition.

  • rel:

    object:relatives. Contains API URIs corresponding to this composition and its relatives.

    Expect canonical which returns the API resource for each composition.

  • title:

    str. Primary composition title.

  • uri:

    str. Loudr’s unique identifier for the composition.

Sample Composition from the API:

{
  "alias": [],
  "author_names": [
    "Koji Kondo"
  ],
  "authors": [
    {
      "ipi": null,
      "name": "Koji Kondo",
      "role": {
        "code": "CA",
        "id": 1,
        "name": "Composer & Author"
      }
    }
  ],
  "display_name": "Super Mario World Title Theme",
  "id": "abc",
  "kind": "composition",
  "publishers": [
    "Bumbly Bee Publishing Co."
  ],
  "rel": {
    "canonical": "/api/composition/abc"
  },
  "title": "Super Mario World Title Theme",
  "uri": "composition/abc"
}


Usage Reporting

If you are sending royalty payments to publishers via Loudr, you will need to submit periodic Usage Reports which contain this data.

Validation of your Usage Reports happens in step 3 of the integration roadmap.

Usage Report Format

The usage report is a multi-line JSON file containing data required to pay royalties to rights holders.

Aggregating Report Lines We will require this information to be aggregated by these identifying fields:

  • Vendor ID of Sound Recording
  • Type of Configuration
  • Units
  • Date of Fixation/Reproduction
  • Per-Play License Fee
  • Platform/Store of Reproduction (i.e. iTunes)
  • Country of Fixation or Reproduction (i.e. US for now)

As such, in a report you may yield multiple lines for a single piece of content. For example, if my-vendor-id plays ten times with two different per-play fees, you would generate two lines, grouping the plays by the fields mentioned above:

{"vendor_id": "my-vendor-id", "license_fee": "0.0054", "units": 6, "date": "2015-05-01", "config": "stream", "country": "US", "store": "itunes"}
{"vendor_id": "my-vendor-id", "license_fee": "0.0064", "units": 4, "date": "2015-05-01", "config": "stream", "country": "US", "store": "itunes"}

Report Segmentation Due to the complexity of the reports, you may segment the your report into multiple files as you please. If you have a lot of usage data, we reccommend a segmenting your data into weekly or daily groupings. (or more, if desired) Each uploaded file will appear with attached royalties and service fee for your review before finalizing and adding the cost to your monthly invoice.

Report Compression Due to the required granularity of the report, these usage reports may be very large. To mitigate this, we strongly encourage you to gzip your reports before delivering.

The ideal filename for delivery will ultimately look similar to usage-report-YYYY-MM-DD.json.gz.

Report Delivery Initially, delivery of usage reports will be executed via your client dashboard, which we will have available at a later date. As the size of reports grow, we may support delivery over SFTP at a later date.

Usage Report Objects

Each line of the report should be a single JSON object with no trailing commas or enclosing array brackets around all items.

A usage report object is comprised of license identifier & usage data.

License ID One, and only one of the following identifiers is required to match your usage to your licensed content. We recommend the vendor_id.

  • vendor_id:

    str. Vendor ID.

  • loudr_uri:

    str. Loudr URI of request.

  • isrc:

    str. ISRC of content. Only use this if you do not have the vendor_id or loudr_uri explicitly.

Usage data

  • license_fee:

    str. Applicable per-play Music License Fee.

    Determined by Client based on internal service information.

    A string intepretation of this decimal value in USD is expected.

    Please avoid using float values, as json parsing may lose accuracy of high-precision values.

    This value may be omitted depending on how your deal with Loudr is structured. We may be ultimately responsible for determining this value, in which case you may omit this property, or provide a null value.

  • fee_currency:

    str. Not yet supported. License fee currency.

    "USD" is implied at this time, this field should be omitted.

  • config:

    str. Type of configuration made pursuant to the license.

    We use this value to communicate how content was delivered to publishers, in addition to asserting that license configurations were are correctly fulfilled.

    Expected values include: "stream" - interactive stream "download" or "dpd" - digital permanent download

  • units:

    int. Number of fixations or reproductions made pursuant to the license.

    This integer is multiplied by the license_fee to determine the payout due to publishers.

  • country:

    str. Country of fixation or reproduction.

    This value should be a 2 character ISO-3166 country code. Right now, we only expect the value US - for United States.

  • date:

    str. ISO formatted date "YYYY-MM-DD" of content delivery.

  • store:

    str. Name of the distribution outlet which serviced this usage.

    Accepted values are listed below. If you have received royalty revenue from a store we do not have listed below, please contact your business representative.

    List of Stores All accepted values for the store property are contained in stores.json on Loudr’s github.

Line Formatting Each line in the usage report should contain one JSON object, and include UNIX line-endings, ending with \n.

BEST line formatting

{"vendor_id": "my-vendor-id", "license_fee": "0.0054", "units": 6, "date": "2015-05-01", "config": "stream", "country": "US", "store": "itunes"}
{"vendor_id": "my-vendor-id", "license_fee": "0.0064", "units": 4, "date": "2015-05-01", "config": "stream", "country": "US", "store": "itunes"}
{"vendor_id": "my-vendor-id", "license_fee": "0.0064", "units": 9, "date": "2015-05-02", "config": "stream", "country": "US", "store": "itunes"}

OK line formatting

[{"vendor_id": "my-vendor-id", "license_fee": "0.0054", "units": 6, "date": "2015-05-01", "config": "stream", "country": "US", "store": "itunes"},
{"vendor_id": "my-vendor-id", "license_fee": "0.0064", "units": 4, "date": "2015-05-01", "config": "stream", "country": "US", "store": "itunes"},
{"vendor_id": "my-vendor-id", "license_fee": "0.0064", "units": 9, "date": "2015-05-02", "config": "stream", "country": "US", "store": "itunes"}]

BAD line formatting Do NOT send usage reports in multiple lines, or a single line:

[
  {
    "vendor_id": "my-vendor-id",
    "license_fee": "0.0054",
    "units": 6,
    "date": "2015-05-01",
    "config": "stream",
    "country": "US",
    "store": "itunes"
  },
  {
    "vendor_id": "my-vendor-id",
    "license_fee": "0.0064",
    "units": 4,
    "date": "2015-05-01",
    "config": "stream",
    "country": "US",
    "store": "itunes"
  },
  {
    "vendor_id": "my-vendor-id",
    "license_fee": "0.0064",
    "units": 9,
    "date": "2015-05-02",
    "config": "stream",
    "country": "US",
    "store": "itunes"
  }
]

Also wrong

[{"vendor_id":"my-vendor-id","license_fee":"0.0054","units":6,"date":"2015-05-01","config":"stream","country":"US"},{"vendor_id":"my-vendor-id","license_fee":"0.0064","units":4,"date":"2015-05-01","config":"stream","country":"US"},{"vendor_id":"my-vendor-id","license_fee":"0.0064","units":9,"date":"2015-05-02","config":"stream","country":"US"}]

Discrepencies between expected royalty costs, and actual royalty costs You may note that some usage reports yield a larger royalty cost than the sum of all provided license_fee * units. This is due to the fact that some recordings might be identified as medleys, and render more royalties than the standard calculation. You can verify this with the royalty_rates property of your request in the API.


Bulk Request Delivery Format Specifications

Partners may deliver requests in bulk to Loudr via Email or SFTP.

For partners using the Web API We ask Web API integrating partners to generate a bulk request file when integrating with our API to complete our integration roadmap and acquire an access token. For this, we expect you to use our JSON Format, explained below, which will match the metadata you send to the API.

JSON Format

Bulk requests may be delivered in a multi-line JSON file, each line containing a Sound Recording Object, and matches the format used by the Web API.

For more details, see Sound Recording & License Requests Object Schema for delivery.

See the example requests-bulk.json on our github.

Note to Existing Partners There is an older “bulk request” JSON format which you may be using containing a compositions object and matching the “v1 API”. You may continue to use this format indefinitely.

See the v1 request docs and example v1 json on our github.

CSV Format

You may create a CSV to deliver your requests. See the example requests-bulk.csv on our github.

Multiple artists and authors should be denoted with the SEMICOLON character, and all fields containing commas may be wrapped in quotes ("). (See request 2 in the above example.)

As a rule, UPCs are best formatted as strings (and presented in quotes), to prevent modern editors from reading scientific notation.

Example:

"Here’s a ""quote"" in a field"

will appear as

Here's a "quote" in a field