# info.description
Read and write royalty accounting data in Habitat: catalog, deals, payees, expenses, royalty statements, earnings and payments.

Every request needs a team API token. Send it in the `Authorization` header as `Token habitatkey_<token>`. Create a token in the Habitat app under Settings, then API. A token expires 90 days after it is issued.

A token is scoped to exactly one team. The API never returns data that belongs to another team.

# paths./api/albums/.get.description
Allow permanent deletion only when a catalog record has no dependencies.

Requires the `content:read` scope.

# paths./api/albums/.get.parameters[].description
A page number within the paginated result set.

# paths./api/albums/.post.description
Allow permanent deletion only when a catalog record has no dependencies.

Requires the `content:write` scope.

# paths./api/albums/{id}/.get.description
Allow permanent deletion only when a catalog record has no dependencies.

Requires the `content:read` scope.

# paths./api/albums/{id}/.get.parameters[].description
A unique integer value identifying this album.

# paths./api/albums/{id}/.put.description
Allow permanent deletion only when a catalog record has no dependencies.

Requires the `content:write` scope.

# paths./api/albums/{id}/.put.parameters[].description
A unique integer value identifying this album.

# paths./api/albums/{id}/.patch.description
Allow permanent deletion only when a catalog record has no dependencies.

Requires the `content:write` scope.

# paths./api/albums/{id}/.patch.parameters[].description
A unique integer value identifying this album.

# paths./api/albums/{id}/.delete.description
Allow permanent deletion only when a catalog record has no dependencies.

Requires the `content:write` scope.

# paths./api/albums/{id}/.delete.parameters[].description
A unique integer value identifying this album.

# paths./api/artist-types/.get.description
Shared team scope for uniform team-owned model endpoints.

Requires the `content:read` scope.

# paths./api/artist-types/.get.parameters[].description
A page number within the paginated result set.

# paths./api/artist-types/.post.description
Shared team scope for uniform team-owned model endpoints.

Requires the `content:write` scope.

# paths./api/artist-types/{id}/.get.description
Shared team scope for uniform team-owned model endpoints.

Requires the `content:read` scope.

# paths./api/artist-types/{id}/.get.parameters[].description
A unique integer value identifying this artist type.

# paths./api/artist-types/{id}/.put.description
Shared team scope for uniform team-owned model endpoints.

Requires the `content:write` scope.

# paths./api/artist-types/{id}/.put.parameters[].description
A unique integer value identifying this artist type.

# paths./api/artist-types/{id}/.patch.description
Shared team scope for uniform team-owned model endpoints.

Requires the `content:write` scope.

# paths./api/artist-types/{id}/.patch.parameters[].description
A unique integer value identifying this artist type.

# paths./api/artist-types/{id}/.delete.description
Shared team scope for uniform team-owned model endpoints.

Requires the `content:write` scope.

# paths./api/artist-types/{id}/.delete.parameters[].description
A unique integer value identifying this artist type.

# paths./api/artists/.get.description
Allow permanent deletion only when a catalog record has no dependencies.

Requires the `content:read` scope.

# paths./api/artists/.get.parameters[].description
A page number within the paginated result set.

# paths./api/artists/.post.description
Allow permanent deletion only when a catalog record has no dependencies.

Requires the `content:write` scope.

# paths./api/artists/{id}/.get.description
Allow permanent deletion only when a catalog record has no dependencies.

Requires the `content:read` scope.

# paths./api/artists/{id}/.get.parameters[].description
A unique integer value identifying this artist.

# paths./api/artists/{id}/.put.description
Allow permanent deletion only when a catalog record has no dependencies.

Requires the `content:write` scope.

# paths./api/artists/{id}/.put.parameters[].description
A unique integer value identifying this artist.

# paths./api/artists/{id}/.patch.description
Allow permanent deletion only when a catalog record has no dependencies.

Requires the `content:write` scope.

# paths./api/artists/{id}/.patch.parameters[].description
A unique integer value identifying this artist.

# paths./api/artists/{id}/.delete.description
Allow permanent deletion only when a catalog record has no dependencies.

Requires the `content:write` scope.

# paths./api/artists/{id}/.delete.parameters[].description
A unique integer value identifying this artist.

# paths./api/composition-splits/.get.description
Shared team scope for uniform team-owned model endpoints.

Requires the `content:read` scope.

# paths./api/composition-splits/.get.parameters[].description
A page number within the paginated result set.

# paths./api/composition-splits/.post.description
Shared team scope for uniform team-owned model endpoints.

Requires the `content:write` scope.

# paths./api/composition-splits/{id}/.get.description
Shared team scope for uniform team-owned model endpoints.

Requires the `content:read` scope.

# paths./api/composition-splits/{id}/.get.parameters[].description
A unique integer value identifying this composition split.

# paths./api/composition-splits/{id}/.put.description
Shared team scope for uniform team-owned model endpoints.

Requires the `content:write` scope.

# paths./api/composition-splits/{id}/.put.parameters[].description
A unique integer value identifying this composition split.

# paths./api/composition-splits/{id}/.patch.description
Shared team scope for uniform team-owned model endpoints.

Requires the `content:write` scope.

# paths./api/composition-splits/{id}/.patch.parameters[].description
A unique integer value identifying this composition split.

# paths./api/composition-splits/{id}/.delete.description
Shared team scope for uniform team-owned model endpoints.

Requires the `content:write` scope.

# paths./api/composition-splits/{id}/.delete.parameters[].description
A unique integer value identifying this composition split.

# paths./api/compositions/.get.description
Allow permanent deletion only when a catalog record has no dependencies.

Requires the `content:read` scope.

# paths./api/compositions/.get.parameters[].description
A page number within the paginated result set.

# paths./api/compositions/.post.description
Allow permanent deletion only when a catalog record has no dependencies.

Requires the `content:write` scope.

# paths./api/compositions/{id}/.get.description
Allow permanent deletion only when a catalog record has no dependencies.

Requires the `content:read` scope.

# paths./api/compositions/{id}/.get.parameters[].description
A unique integer value identifying this composition.

# paths./api/compositions/{id}/.put.description
Allow permanent deletion only when a catalog record has no dependencies.

Requires the `content:write` scope.

# paths./api/compositions/{id}/.put.parameters[].description
A unique integer value identifying this composition.

# paths./api/compositions/{id}/.patch.description
Allow permanent deletion only when a catalog record has no dependencies.

Requires the `content:write` scope.

# paths./api/compositions/{id}/.patch.parameters[].description
A unique integer value identifying this composition.

# paths./api/compositions/{id}/.delete.description
Allow permanent deletion only when a catalog record has no dependencies.

Requires the `content:write` scope.

# paths./api/compositions/{id}/.delete.parameters[].description
A unique integer value identifying this composition.

# paths./api/deals/.get.parameters[].description
A page number within the paginated result set.

# paths./api/deals/{id}/.get.parameters[].description
A unique integer value identifying this deal.

# paths./api/deals/{id}/.put.parameters[].description
A unique integer value identifying this deal.

# paths./api/deals/{id}/.patch.parameters[].description
A unique integer value identifying this deal.

# paths./api/deals/{id}/.delete.parameters[].description
A unique integer value identifying this deal.

# paths./api/deals/{id}/add-composition-split/.post.description
Create a composition split and attach it to a compositions deal. See ``deal_composition_splits.add_composition_split``.

Requires the `deals:write` scope.

# paths./api/deals/{id}/add-composition-split/.post.summary
Add a composition split to a compositions deal

# paths./api/deals/{id}/add-composition-split/.post.parameters[].description
A unique integer value identifying this deal.

# paths./api/deals/{id}/add-composition-split/.post.responses.400.description
Not a compositions deal, a required field is missing, or the split already exists.

# paths./api/deals/{id}/add-composition-split/.post.responses.404.description
The composition, songwriter or publisher does not belong to your team.

# paths./api/deals/{id}/add-merch-items/.post.description
Add merch items to a merch deal.
Only available for merch deals.

Requires the `deals:write` scope.

# paths./api/deals/{id}/add-merch-items/.post.parameters[].description
A unique integer value identifying this deal.

# paths./api/deals/{id}/add-merch-items/.post.responses.201.content.application/json.schema.properties.already_linked.description
Names of the rows that were skipped, not their ids.

# paths./api/deals/{id}/add-merch-items/.post.responses.201.description
The items were linked. `already_linked` lists the ones that were on the deal already.

# paths./api/deals/{id}/add-merch-items/.post.responses.400.description
Not a merch deal, the list is empty, or an item does not belong to your team.

# paths./api/deals/{id}/add-payee/.post.description
Add a payee to a deal with a share percentage. See ``deal_shares.add_payee_to_deal``.

Requires the `deals:write` scope.

# paths./api/deals/{id}/add-payee/.post.parameters[].description
A unique integer value identifying this deal.

# paths./api/deals/{id}/add-payee/.post.responses.400.description
The payload is invalid for this deal type, or the payee is already on it.

# paths./api/deals/{id}/add-records/.post.description
Add records to a recordings deal.
Only available for recordings deals.

Requires the `deals:write` scope.

# paths./api/deals/{id}/add-records/.post.parameters[].description
A unique integer value identifying this deal.

# paths./api/deals/{id}/add-records/.post.responses.201.content.application/json.schema.properties.already_linked.description
Names of the rows that were skipped, not their ids.

# paths./api/deals/{id}/add-records/.post.responses.201.description
The tracks were linked. `already_linked` lists the ones that were on the deal already.

# paths./api/deals/{id}/add-records/.post.responses.400.description
Not a recordings deal, the list is empty, or a track does not belong to your team.

# paths./api/deals/{id}/add-split/.post.description
Add a payee share to a recordings deal with territory, usage type and store scope. See ``deal_shares.add_split_to_deal``.

Requires the `deals:write` scope.

# paths./api/deals/{id}/add-split/.post.parameters[].description
A unique integer value identifying this deal.

# paths./api/deals/{id}/add-split/.post.responses.201.content.application/json.schema.properties.payee_share.properties.stores.description
Null when the share is not limited to named stores.

# paths./api/deals/{id}/add-split/.post.responses.400.description
The payload is invalid, or the payee is already on this split.

# paths./api/deals/{id}/catalog/.get.description
Get the catalog (items) associated with this deal.

For recordings deals: returns list of records directly linked via MasterDeal.record
For compositions deals: returns list of composition splits directly linked via CompositionDeal.compositionsplit
For merch deals: returns list of merch items directly linked via MerchItem.merch_deal

Requires the `deals:read` scope.

# paths./api/deals/{id}/catalog/.get.parameters[].description
A unique integer value identifying this deal.

# paths./api/deals/{id}/catalog/.get.responses.200.description
The keys inside each item depend on `catalog_type`.

# paths./api/deals/{id}/configure-advanced/.post.description
Set the advanced terms of a recordings deal. See ``deal_shares.configure_advanced_deal``.

Requires the `deals:write` scope.

# paths./api/deals/{id}/configure-advanced/.post.summary
Set the advanced terms of a recordings deal

# paths./api/deals/{id}/configure-advanced/.post.parameters[].description
A unique integer value identifying this deal.

# paths./api/deals/{id}/configure-advanced/.post.responses.400.description
Not a recordings deal, or a value is outside its allowed set.

# paths./api/deals/{id}/remove-composition-split/{split_id}/.delete.description
Detach a composition split from the deal. See ``deal_composition_splits.remove_composition_split``.

Requires the `deals:write` scope.

# paths./api/deals/{id}/remove-composition-split/{split_id}/.delete.summary
Detach a composition split from a compositions deal

# paths./api/deals/{id}/remove-composition-split/{split_id}/.delete.parameters[].description
A unique integer value identifying this deal.

# paths./api/deals/{id}/remove-composition-split/{split_id}/.delete.parameters[].description
Identifier of a composition split on this deal.

# paths./api/deals/{id}/remove-composition-split/{split_id}/.delete.responses.200.description
The split was detached. It is catalog content, so it survives leaving the deal.

# paths./api/deals/{id}/remove-merch-items/.delete.description
Remove merch items from a merch deal.
Only available for merch deals.

Requires the `deals:write` scope.

# paths./api/deals/{id}/remove-merch-items/.delete.parameters[].description
A unique integer value identifying this deal.

# paths./api/deals/{id}/remove-merch-items/.delete.responses.200.content.application/json.schema.properties.not_linked.description
Names of the rows that were skipped, not their ids.

# paths./api/deals/{id}/remove-merch-items/.delete.responses.200.description
The items were unlinked. `not_linked` lists the ones that were not on the deal.

# paths./api/deals/{id}/remove-merch-items/.delete.responses.400.description
Not a merch deal, the list is empty, or an item does not belong to your team.

# paths./api/deals/{id}/remove-payee/{payee_id}/.delete.description
Remove a payee from a deal. See ``deal_shares.remove_payee_from_deal``.

Requires the `deals:write` scope.

# paths./api/deals/{id}/remove-payee/{payee_id}/.delete.parameters[].description
A unique integer value identifying this deal.

# paths./api/deals/{id}/remove-records/.delete.description
Remove records from a recordings deal.
Only available for recordings deals.

Requires the `deals:write` scope.

# paths./api/deals/{id}/remove-records/.delete.parameters[].description
A unique integer value identifying this deal.

# paths./api/deals/{id}/remove-records/.delete.responses.200.content.application/json.schema.properties.not_linked.description
Names of the rows that were skipped, not their ids.

# paths./api/deals/{id}/remove-records/.delete.responses.200.description
The tracks were unlinked. `not_linked` lists the ones that were not on the deal.

# paths./api/deals/{id}/remove-records/.delete.responses.400.description
Not a recordings deal, the list is empty, or a track does not belong to your team.

# paths./api/deals/{id}/update-composition-split/{split_id}/.patch.description
Change a composition split attached to the deal. See ``deal_composition_splits.update_composition_split``.

Requires the `deals:write` scope.

# paths./api/deals/{id}/update-composition-split/{split_id}/.patch.summary
Change a composition split on a compositions deal

# paths./api/deals/{id}/update-composition-split/{split_id}/.patch.parameters[].description
A unique integer value identifying this deal.

# paths./api/deals/{id}/update-composition-split/{split_id}/.patch.parameters[].description
Identifier of a composition split on this deal.

# paths./api/deals/{id}/update-composition-split/{split_id}/.patch.responses.400.description
Not a compositions deal, or writer_share is outside 0 to 100.

# paths./api/deals/{id}/update-composition-split/{split_id}/.patch.responses.404.description
The split is not on this deal, or the publisher does not belong to your team.

# paths./api/deals/{id}/update-payee/{payee_id}/.patch.description
Change a payee's percentage, and on recordings deals its type. See ``deal_shares.update_payee_in_deal``.

Requires the `deals:write` scope.

# paths./api/deals/{id}/update-payee/{payee_id}/.patch.parameters[].description
A unique integer value identifying this deal.

# paths./api/exchange-rates/.get.parameters[].description
A page number within the paginated result set.

# paths./api/exchange-rates/{id}/.get.parameters[].description
A unique integer value identifying this royalty statement exchange rate.

# paths./api/exchange-rates/{id}/.put.parameters[].description
A unique integer value identifying this royalty statement exchange rate.

# paths./api/exchange-rates/{id}/.patch.parameters[].description
A unique integer value identifying this royalty statement exchange rate.

# paths./api/exchange-rates/{id}/.delete.parameters[].description
A unique integer value identifying this royalty statement exchange rate.

# paths./api/expense-payee-levels/.get.description
Shared team scope for uniform team-owned model endpoints.

Requires the `expenses:read` scope.

# paths./api/expense-payee-levels/.get.parameters[].description
A page number within the paginated result set.

# paths./api/expense-payee-levels/.post.description
Shared team scope for uniform team-owned model endpoints.

Requires the `expenses:write` scope.

# paths./api/expense-payee-levels/{id}/.get.description
Shared team scope for uniform team-owned model endpoints.

Requires the `expenses:read` scope.

# paths./api/expense-payee-levels/{id}/.get.parameters[].description
A unique integer value identifying this expense payee level.

# paths./api/expense-payee-levels/{id}/.put.description
Shared team scope for uniform team-owned model endpoints.

Requires the `expenses:write` scope.

# paths./api/expense-payee-levels/{id}/.put.parameters[].description
A unique integer value identifying this expense payee level.

# paths./api/expense-payee-levels/{id}/.patch.description
Shared team scope for uniform team-owned model endpoints.

Requires the `expenses:write` scope.

# paths./api/expense-payee-levels/{id}/.patch.parameters[].description
A unique integer value identifying this expense payee level.

# paths./api/expense-payee-levels/{id}/.delete.description
Shared team scope for uniform team-owned model endpoints.

Requires the `expenses:write` scope.

# paths./api/expense-payee-levels/{id}/.delete.parameters[].description
A unique integer value identifying this expense payee level.

# paths./api/health/.get.description
Returns 200 while the API is up. Needs no token. Use it as a liveness probe.

# paths./api/isrcs/.get.description
Allow permanent deletion only when a catalog record has no dependencies.

Requires the `content:read` scope.

# paths./api/isrcs/.get.parameters[].description
A page number within the paginated result set.

# paths./api/isrcs/.post.description
Allow permanent deletion only when a catalog record has no dependencies.

Requires the `content:write` scope.

# paths./api/isrcs/{id}/.get.description
Allow permanent deletion only when a catalog record has no dependencies.

Requires the `content:read` scope.

# paths./api/isrcs/{id}/.get.parameters[].description
A unique integer value identifying this isrc.

# paths./api/isrcs/{id}/.put.description
Allow permanent deletion only when a catalog record has no dependencies.

Requires the `content:write` scope.

# paths./api/isrcs/{id}/.put.parameters[].description
A unique integer value identifying this isrc.

# paths./api/isrcs/{id}/.patch.description
Allow permanent deletion only when a catalog record has no dependencies.

Requires the `content:write` scope.

# paths./api/isrcs/{id}/.patch.parameters[].description
A unique integer value identifying this isrc.

# paths./api/isrcs/{id}/.delete.description
Allow permanent deletion only when a catalog record has no dependencies.

Requires the `content:write` scope.

# paths./api/isrcs/{id}/.delete.parameters[].description
A unique integer value identifying this isrc.

# paths./api/isrcs/without-products/.get.description
List ISRCs that are not linked to any product.

Requires the `content:read` scope.

# paths./api/merch-items/.get.description
Allow permanent deletion only when a catalog record has no dependencies.

Requires the `content:read` scope.

# paths./api/merch-items/.get.parameters[].description
A page number within the paginated result set.

# paths./api/merch-items/.post.description
Allow permanent deletion only when a catalog record has no dependencies.

Requires the `content:write` scope.

# paths./api/merch-items/{id}/.get.description
Allow permanent deletion only when a catalog record has no dependencies.

Requires the `content:read` scope.

# paths./api/merch-items/{id}/.get.parameters[].description
A unique integer value identifying this merch item.

# paths./api/merch-items/{id}/.put.description
Allow permanent deletion only when a catalog record has no dependencies.

Requires the `content:write` scope.

# paths./api/merch-items/{id}/.put.parameters[].description
A unique integer value identifying this merch item.

# paths./api/merch-items/{id}/.patch.description
Allow permanent deletion only when a catalog record has no dependencies.

Requires the `content:write` scope.

# paths./api/merch-items/{id}/.patch.parameters[].description
A unique integer value identifying this merch item.

# paths./api/merch-items/{id}/.delete.description
Allow permanent deletion only when a catalog record has no dependencies.

Requires the `content:write` scope.

# paths./api/merch-items/{id}/.delete.parameters[].description
A unique integer value identifying this merch item.

# paths./api/merch-items/{id}/merge/.post.description
Merge this merch item into another merch item for the same team.

Requires the `content:write` scope.

# paths./api/merch-items/{id}/merge/.post.parameters[].description
A unique integer value identifying this merch item.

# paths./api/merch-items/{id}/merge/.post.responses.400.description
The target is missing, not an integer, or the same item.

# paths./api/merch-items/incomplete/.get.description
List merch items that do not have a merch deal share.

Requires the `content:read` scope.

# paths./api/oneoff-income-composition/.get.parameters[].description
A page number within the paginated result set.

# paths./api/oneoff-income-composition/{id}/.get.parameters[].description
A unique integer value identifying this one off income composition.

# paths./api/oneoff-income-composition/{id}/.put.parameters[].description
A unique integer value identifying this one off income composition.

# paths./api/oneoff-income-composition/{id}/.patch.parameters[].description
A unique integer value identifying this one off income composition.

# paths./api/oneoff-income-composition/{id}/.delete.parameters[].description
A unique integer value identifying this one off income composition.

# paths./api/oneoff-income-master/.get.parameters[].description
A page number within the paginated result set.

# paths./api/oneoff-income-master/{id}/.get.parameters[].description
A unique integer value identifying this one off income master.

# paths./api/oneoff-income-master/{id}/.put.parameters[].description
A unique integer value identifying this one off income master.

# paths./api/oneoff-income-master/{id}/.patch.parameters[].description
A unique integer value identifying this one off income master.

# paths./api/oneoff-income-master/{id}/.delete.parameters[].description
A unique integer value identifying this one off income master.

# paths./api/oneoff-income-merch/.get.parameters[].description
A page number within the paginated result set.

# paths./api/oneoff-income-merch/{id}/.get.parameters[].description
A unique integer value identifying this one off income merch.

# paths./api/oneoff-income-merch/{id}/.put.parameters[].description
A unique integer value identifying this one off income merch.

# paths./api/oneoff-income-merch/{id}/.patch.parameters[].description
A unique integer value identifying this one off income merch.

# paths./api/oneoff-income-merch/{id}/.delete.parameters[].description
A unique integer value identifying this one off income merch.

# paths./api/oneoff-income-payee/.get.description
CRUD API for direct-payee voucher income.

Requires the `revenue_streams:read` scope.

# paths./api/oneoff-income-payee/.get.parameters[].description
A page number within the paginated result set.

# paths./api/oneoff-income-payee/.post.description
CRUD API for direct-payee voucher income.

Requires the `revenue_streams:write` scope.

# paths./api/oneoff-income-payee/{id}/.get.description
CRUD API for direct-payee voucher income.

Requires the `revenue_streams:read` scope.

# paths./api/oneoff-income-payee/{id}/.get.parameters[].description
A unique integer value identifying this one off income payee.

# paths./api/oneoff-income-payee/{id}/.put.description
CRUD API for direct-payee voucher income.

Requires the `revenue_streams:write` scope.

# paths./api/oneoff-income-payee/{id}/.put.parameters[].description
A unique integer value identifying this one off income payee.

# paths./api/oneoff-income-payee/{id}/.patch.description
CRUD API for direct-payee voucher income.

Requires the `revenue_streams:write` scope.

# paths./api/oneoff-income-payee/{id}/.patch.parameters[].description
A unique integer value identifying this one off income payee.

# paths./api/oneoff-income-payee/{id}/.delete.description
CRUD API for direct-payee voucher income.

Requires the `revenue_streams:write` scope.

# paths./api/oneoff-income-payee/{id}/.delete.parameters[].description
A unique integer value identifying this one off income payee.

# paths./api/overall-period-payee-earnings/.get.parameters[].description
A page number within the paginated result set.

# paths./api/overall-period-payee-earnings/{id}/.get.parameters[].description
A unique integer value identifying this overall period payee earnings.

# paths./api/payee-report-csv/.get.description
Returns a download URL for a payee's period report as a CSV. Generate the batch of reports for the period in the Habitat app first. Until the batch finishes, this endpoint reports that the report is not ready.

Requires the `statements:read` scope.

# paths./api/payee-report-csv/.get.parameters[].description
Identifier of a payee that belongs to the authenticated team.

# paths./api/payee-report-csv/.get.responses.200.description
A time-limited download URL for the CSV report.

# paths./api/payee-report-csv/.get.responses.400.content.application/json.schema.properties.status.description
Machine-readable reason. Present when the report is missing or unfinished.

# paths./api/payee-report-csv/.get.responses.400.description
A parameter is missing, or the report is not finished yet.

# paths./api/payee-report-csv/.get.responses.401.content.application/json.schema.properties.status.description
Machine-readable reason. Present when the report is missing or unfinished.

# paths./api/payee-report-csv/.get.responses.404.content.application/json.schema.properties.status.description
Machine-readable reason. Present when the report is missing or unfinished.

# paths./api/payee-report-csv/.get.responses.404.description
No such payee, or no report for that period.

# paths./api/payee-report-csv/.get.responses.500.content.application/json.schema.properties.status.description
Machine-readable reason. Present when the report is missing or unfinished.

# paths./api/payee-report-pdf/.get.description
Returns a download URL for a payee's period report as a PDF. Generate the batch of reports for the period in the Habitat app first. Until the batch finishes, this endpoint reports that the report is not ready.

Requires the `statements:read` scope.

# paths./api/payee-report-pdf/.get.parameters[].description
Identifier of a payee that belongs to the authenticated team.

# paths./api/payee-report-pdf/.get.responses.200.description
A time-limited download URL for the PDF report.

# paths./api/payee-report-pdf/.get.responses.400.content.application/json.schema.properties.status.description
Machine-readable reason. Present when the report is missing or unfinished.

# paths./api/payee-report-pdf/.get.responses.400.description
A parameter is missing, or the report is not finished yet.

# paths./api/payee-report-pdf/.get.responses.401.content.application/json.schema.properties.status.description
Machine-readable reason. Present when the report is missing or unfinished.

# paths./api/payee-report-pdf/.get.responses.404.content.application/json.schema.properties.status.description
Machine-readable reason. Present when the report is missing or unfinished.

# paths./api/payee-report-pdf/.get.responses.404.description
No such payee, or no report for that period.

# paths./api/payee-report-pdf/.get.responses.500.content.application/json.schema.properties.status.description
Machine-readable reason. Present when the report is missing or unfinished.

# paths./api/payee-track-dsp-earnings/.get.description
Per-DSP, per-track royalty earnings for one payee, with reporting-period distinctions.

``GET /api/payee-track-dsp-earnings/?payee_id={id}[&period={code}][&isrc={a,b}]``

Returns one row per (source, reporting period, transaction period, DSP, usage type,
track, deal) of the payee's recordings earnings — the same numbers as the payee's
period/lifetime statement. This is the finest grain that supports both a per-DSP
rollup (sum by ``store``, splitting ``quantity`` on ``usage_type`` into streams vs
downloads) and per-track views.

- ``payee_id`` (required): scoped to the authenticated team; another team's payee 404s.
- ``period`` (optional): a reporting-period code (e.g. ``2024-04``); omit for lifetime.
- ``isrc`` (optional): comma-separated ISRCs to pull several tracks in one call.

Amounts stay in the payee's base currency; the additive ``origin_currency`` /
``converted_currency`` / ``exchange_rate`` / ``is_converted`` /
``converted_gross_revenue`` / ``converted_net_royalty`` fields convert to the
payee's display currency at an approximate daily rate (a period request converts at
the period's financial date). On a rate cache miss ``exchange_rate`` is ``null``,
``is_converted`` is ``false`` and amounts stay in the base currency.

Requires the `statements:read` scope.

# paths./api/payee-track-dsp-earnings/.get.parameters[].description
A page number within the paginated result set.

# paths./api/payees/.get.parameters[].description
A page number within the paginated result set.

# paths./api/payees/{id}/.get.parameters[].description
A unique integer value identifying this payee.

# paths./api/payees/{id}/.put.parameters[].description
A unique integer value identifying this payee.

# paths./api/payees/{id}/.patch.parameters[].description
A unique integer value identifying this payee.

# paths./api/payees/{id}/.delete.parameters[].description
A unique integer value identifying this payee.

# paths./api/payees/{id}/display-currency/.patch.description
Set (or clear) only a payee's display currency.

A focused, guarded alternative to a generic PATCH: it touches nothing but
``display_currency`` (never the base currency, balances, or name). Send
``{"display_currency": "INR"}`` to set it, or ``{"display_currency": null}`` to
reset it to the payee's base currency (display_currency is never null).

Requires the `payees:write` scope.

# paths./api/payees/{id}/display-currency/.patch.parameters[].description
A unique integer value identifying this payee.

# paths./api/payments/.get.parameters[].description
A page number within the paginated result set.

# paths./api/payments/{id}/.get.parameters[].description
A unique integer value identifying this payment.

# paths./api/payments/{id}/.put.parameters[].description
A unique integer value identifying this payment.

# paths./api/payments/{id}/.patch.parameters[].description
A unique integer value identifying this payment.

# paths./api/payments/{id}/.delete.parameters[].description
A unique integer value identifying this payment.

# paths./api/product-art/.get.description
Shared team scope for uniform team-owned model endpoints.

Requires the `content:read` scope.

# paths./api/product-art/.get.parameters[].description
A page number within the paginated result set.

# paths./api/product-art/.post.description
Shared team scope for uniform team-owned model endpoints.

Requires the `content:write` scope.

# paths./api/product-art/{id}/.get.description
Shared team scope for uniform team-owned model endpoints.

Requires the `content:read` scope.

# paths./api/product-art/{id}/.get.parameters[].description
A unique integer value identifying this product art.

# paths./api/product-art/{id}/.put.description
Shared team scope for uniform team-owned model endpoints.

Requires the `content:write` scope.

# paths./api/product-art/{id}/.put.parameters[].description
A unique integer value identifying this product art.

# paths./api/product-art/{id}/.patch.description
Shared team scope for uniform team-owned model endpoints.

Requires the `content:write` scope.

# paths./api/product-art/{id}/.patch.parameters[].description
A unique integer value identifying this product art.

# paths./api/product-art/{id}/.delete.description
Shared team scope for uniform team-owned model endpoints.

Requires the `content:write` scope.

# paths./api/product-art/{id}/.delete.parameters[].description
A unique integer value identifying this product art.

# paths./api/product-isrc-info/.get.parameters[].description
A page number within the paginated result set.

# paths./api/product-isrc-info/{id}/.get.parameters[].description
A unique integer value identifying this product isrc info.

# paths./api/product-isrc-info/{id}/.put.parameters[].description
A unique integer value identifying this product isrc info.

# paths./api/product-isrc-info/{id}/.patch.parameters[].description
A unique integer value identifying this product isrc info.

# paths./api/product-isrc-info/{id}/.delete.parameters[].description
A unique integer value identifying this product isrc info.

# paths./api/products/.get.parameters[].description
A page number within the paginated result set.

# paths./api/products/{id}/.get.parameters[].description
A unique integer value identifying this product.

# paths./api/products/{id}/.put.parameters[].description
A unique integer value identifying this product.

# paths./api/products/{id}/.patch.parameters[].description
A unique integer value identifying this product.

# paths./api/products/{id}/.delete.parameters[].description
A unique integer value identifying this product.

# paths./api/products/incomplete/.get.description
List products that have no track assignments (ProductIsrcInfo).

Requires the `content:read` scope.

# paths./api/publishers/.get.description
Allow permanent deletion only when a catalog record has no dependencies.

Requires the `content:read` scope.

# paths./api/publishers/.get.parameters[].description
A page number within the paginated result set.

# paths./api/publishers/.post.description
Allow permanent deletion only when a catalog record has no dependencies.

Requires the `content:write` scope.

# paths./api/publishers/{id}/.get.description
Allow permanent deletion only when a catalog record has no dependencies.

Requires the `content:read` scope.

# paths./api/publishers/{id}/.get.parameters[].description
A unique integer value identifying this publisher.

# paths./api/publishers/{id}/.put.description
Allow permanent deletion only when a catalog record has no dependencies.

Requires the `content:write` scope.

# paths./api/publishers/{id}/.put.parameters[].description
A unique integer value identifying this publisher.

# paths./api/publishers/{id}/.patch.description
Allow permanent deletion only when a catalog record has no dependencies.

Requires the `content:write` scope.

# paths./api/publishers/{id}/.patch.parameters[].description
A unique integer value identifying this publisher.

# paths./api/publishers/{id}/.delete.description
Allow permanent deletion only when a catalog record has no dependencies.

Requires the `content:write` scope.

# paths./api/publishers/{id}/.delete.parameters[].description
A unique integer value identifying this publisher.

# paths./api/records/.get.description
Deprecated: use TrackViewSet via /api/tracks/ instead.
This viewset uses record_title instead of track_title for backwards compatibility.

Requires the `content:read` scope.

# paths./api/records/.get.parameters[].description
A page number within the paginated result set.

# paths./api/records/.post.description
Deprecated: use TrackViewSet via /api/tracks/ instead.
This viewset uses record_title instead of track_title for backwards compatibility.

Requires the `content:write` scope.

# paths./api/records/{id}/.get.description
Deprecated: use TrackViewSet via /api/tracks/ instead.
This viewset uses record_title instead of track_title for backwards compatibility.

Requires the `content:read` scope.

# paths./api/records/{id}/.get.parameters[].description
A unique integer value identifying this track.

# paths./api/records/{id}/.put.description
Deprecated: use TrackViewSet via /api/tracks/ instead.
This viewset uses record_title instead of track_title for backwards compatibility.

Requires the `content:write` scope.

# paths./api/records/{id}/.put.parameters[].description
A unique integer value identifying this track.

# paths./api/records/{id}/.patch.description
Deprecated: use TrackViewSet via /api/tracks/ instead.
This viewset uses record_title instead of track_title for backwards compatibility.

Requires the `content:write` scope.

# paths./api/records/{id}/.patch.parameters[].description
A unique integer value identifying this track.

# paths./api/records/{id}/.delete.description
Deprecated: use TrackViewSet via /api/tracks/ instead.
This viewset uses record_title instead of track_title for backwards compatibility.

Requires the `content:write` scope.

# paths./api/records/{id}/.delete.parameters[].description
A unique integer value identifying this track.

# paths./api/records/incomplete/.get.description
List tracks that have no ISRC rows.

Requires the `content:read` scope.

# paths./api/reporting-periods/.get.description
Shared team scope for uniform team-owned model endpoints.

Requires the `revenue_streams:read` scope.

# paths./api/reporting-periods/.get.parameters[].description
A page number within the paginated result set.

# paths./api/reporting-periods/.post.description
Shared team scope for uniform team-owned model endpoints.

Requires the `revenue_streams:write` scope.

# paths./api/reporting-periods/{id}/.get.description
Shared team scope for uniform team-owned model endpoints.

Requires the `revenue_streams:read` scope.

# paths./api/reporting-periods/{id}/.get.parameters[].description
A unique integer value identifying this reporting period.

# paths./api/reporting-periods/{id}/.put.description
Shared team scope for uniform team-owned model endpoints.

Requires the `revenue_streams:write` scope.

# paths./api/reporting-periods/{id}/.put.parameters[].description
A unique integer value identifying this reporting period.

# paths./api/reporting-periods/{id}/.patch.description
Shared team scope for uniform team-owned model endpoints.

Requires the `revenue_streams:write` scope.

# paths./api/reporting-periods/{id}/.patch.parameters[].description
A unique integer value identifying this reporting period.

# paths./api/reporting-periods/{id}/.delete.description
Shared team scope for uniform team-owned model endpoints.

Requires the `revenue_streams:write` scope.

# paths./api/reporting-periods/{id}/.delete.parameters[].description
A unique integer value identifying this reporting period.

# paths./api/revenue-streams/.get.description
Revenue Stream ViewSet - Read and Update only, no Create or Delete.
Revenue streams are created automatically when RoyaltyStatements are created.

Requires the `revenue_streams:read` scope.

# paths./api/revenue-streams/.get.parameters[].description
A page number within the paginated result set.

# paths./api/revenue-streams/{id}/.get.description
Revenue Stream ViewSet - Read and Update only, no Create or Delete.
Revenue streams are created automatically when RoyaltyStatements are created.

Requires the `revenue_streams:read` scope.

# paths./api/revenue-streams/{id}/.get.parameters[].description
A unique integer value identifying this revenue stream.

# paths./api/revenue-streams/{id}/.put.description
Revenue Stream ViewSet - Read and Update only, no Create or Delete.
Revenue streams are created automatically when RoyaltyStatements are created.

Requires the `revenue_streams:write` scope.

# paths./api/revenue-streams/{id}/.put.parameters[].description
A unique integer value identifying this revenue stream.

# paths./api/revenue-streams/{id}/.patch.description
Revenue Stream ViewSet - Read and Update only, no Create or Delete.
Revenue streams are created automatically when RoyaltyStatements are created.

Requires the `revenue_streams:write` scope.

# paths./api/revenue-streams/{id}/.patch.parameters[].description
A unique integer value identifying this revenue stream.

# paths./api/royalty-statements/.get.description
Shared team scope for uniform team-owned model endpoints.

Requires the `statements:read` scope.

# paths./api/royalty-statements/.get.parameters[].description
A page number within the paginated result set.

# paths./api/royalty-statements/.post.description
Shared team scope for uniform team-owned model endpoints.

Requires the `statements:write` scope.

# paths./api/royalty-statements/{id}/.get.description
Shared team scope for uniform team-owned model endpoints.

Requires the `statements:read` scope.

# paths./api/royalty-statements/{id}/.get.parameters[].description
A unique integer value identifying this royalty statement.

# paths./api/royalty-statements/{id}/.put.description
Shared team scope for uniform team-owned model endpoints.

Requires the `statements:write` scope.

# paths./api/royalty-statements/{id}/.put.parameters[].description
A unique integer value identifying this royalty statement.

# paths./api/royalty-statements/{id}/.patch.description
Shared team scope for uniform team-owned model endpoints.

Requires the `statements:write` scope.

# paths./api/royalty-statements/{id}/.patch.parameters[].description
A unique integer value identifying this royalty statement.

# paths./api/royalty-statements/{id}/.delete.description
Shared team scope for uniform team-owned model endpoints.

Requires the `statements:write` scope.

# paths./api/royalty-statements/{id}/.delete.parameters[].description
A unique integer value identifying this royalty statement.

# paths./api/royalty-statements/batch-report-details/.get.description
Shared team scope for uniform team-owned model endpoints.

Requires the `statements:read` scope.

# paths./api/royalty-statements/by-isrc/.get.description
Get royalty statements by ISRC code or track_id.

Query Parameters:
- isrc_code (string, optional): ISRC code (12 characters)
- track_id (int, optional): Record ID

At least one parameter is required.

Requires the `statements:read` scope.

# paths./api/royalty-statements/by-isrc/.get.summary
Find royalty statements by ISRC or track

# paths./api/royalty-statements/by-isrc/.get.parameters[].description
A page number within the paginated result set.

# paths./api/royalty-statements/by-isrc/.get.responses.400.description
Neither isrc_code nor track_id was given.

# paths./api/royalty-statements/by-product/.get.description
Get royalty statements by product ID or UPC code.

Query Parameters:
- product_id (int, optional): Direct product ID
- upc (string, optional): UPC code (searches Product model first)

At least one parameter is required.

Requires the `statements:read` scope.

# paths./api/royalty-statements/by-product/.get.summary
Find royalty statements by product or UPC

# paths./api/royalty-statements/by-product/.get.parameters[].description
A page number within the paginated result set.

# paths./api/royalty-statements/delete-batch/.delete.description
Shared team scope for uniform team-owned model endpoints.

Requires the `statements:write` scope.

# paths./api/royalty-statements/generate-lifetime/.post.description
Shared team scope for uniform team-owned model endpoints.

Requires the `statements:write` scope.

# paths./api/royalty-statements/generate-lifetime/.post.responses.200.description
`created` is false when a report for this payee and period already existed.

# paths./api/royalty-statements/generate-lifetime-folder/.post.description
Shared team scope for uniform team-owned model endpoints.

Requires the `statements:write` scope.

# paths./api/royalty-statements/generate-period/.post.description
Shared team scope for uniform team-owned model endpoints.

Requires the `statements:write` scope.

# paths./api/royalty-statements/generate-period/.post.responses.200.description
`created` is false when a report for this payee and period already existed.

# paths./api/royalty-statements/generate-period-folder/.post.description
Shared team scope for uniform team-owned model endpoints.

Requires the `statements:write` scope.

# paths./api/royalty-statements/lifetime-generation-status/.get.description
Shared team scope for uniform team-owned model endpoints.

Requires the `statements:read` scope.

# paths./api/royalty-statements/lifetime-generation-status/.get.summary
Check how one payee's lifetime report is coming along

# paths./api/royalty-statements/lifetime-generation-status/.get.responses.404.description
No such report. A report belonging to another team reads exactly the same, so the response never reveals what another team holds.

# paths./api/royalty-statements/period-generation-status/.get.description
Shared team scope for uniform team-owned model endpoints.

Requires the `statements:read` scope.

# paths./api/royalty-statements/period-generation-status/.get.summary
Check how one payee's period report is coming along

# paths./api/royalty-statements/period-generation-status/.get.responses.404.description
No such report. A report belonging to another team reads exactly the same, so the response never reveals what another team holds.

# paths./api/songwriters/.get.description
Allow permanent deletion only when a catalog record has no dependencies.

Requires the `content:read` scope.

# paths./api/songwriters/.get.parameters[].description
A page number within the paginated result set.

# paths./api/songwriters/.post.description
Allow permanent deletion only when a catalog record has no dependencies.

Requires the `content:write` scope.

# paths./api/songwriters/{id}/.get.description
Allow permanent deletion only when a catalog record has no dependencies.

Requires the `content:read` scope.

# paths./api/songwriters/{id}/.get.parameters[].description
A unique integer value identifying this songwriter.

# paths./api/songwriters/{id}/.put.description
Allow permanent deletion only when a catalog record has no dependencies.

Requires the `content:write` scope.

# paths./api/songwriters/{id}/.put.parameters[].description
A unique integer value identifying this songwriter.

# paths./api/songwriters/{id}/.patch.description
Allow permanent deletion only when a catalog record has no dependencies.

Requires the `content:write` scope.

# paths./api/songwriters/{id}/.patch.parameters[].description
A unique integer value identifying this songwriter.

# paths./api/songwriters/{id}/.delete.description
Allow permanent deletion only when a catalog record has no dependencies.

Requires the `content:write` scope.

# paths./api/songwriters/{id}/.delete.parameters[].description
A unique integer value identifying this songwriter.

# paths./api/statement-sale-items/.get.description
The raw ingested sale lines of royalty statement files, filtered by ISRC or UPC.

``GET /api/statement-sale-items/?isrc={a,b}[&upc={c,d}][&period={code}][&statement_id={id}]``
``GET /api/statement-sale-items/download/?isrc={a,b}...`` for the same rows as a CSV file.

Each row is one ``ProcessedRoyaltydata`` record: the contents of an uploaded statement
file after parsing and standardising, before any deal-share or payee routing. This is
the audit trail behind the aggregated earnings endpoints — use it to answer "which
lines of which file produced this number".

- ``isrc`` (required unless ``upc`` is given): comma-separated ISRC codes. Matching is
  case-insensitive and hyphens are ignored, because Habitat stores ISRCs upper-cased
  with hyphens stripped.
- ``upc`` (optional): comma-separated UPCs. Supplying both widens the result to rows
  matching either.
- ``period`` (optional): a reporting-period code (e.g. ``2024-04``). Omit for all periods.
- ``statement_id`` (optional): limit to one statement.

Every query is scoped to the authenticated team, which is also the table's partition
key. An ISRC, UPC or statement id belonging to another team matches nothing and reads
exactly like an unknown one, so the endpoint never reveals what another team holds.

Requires the `statements:read` scope.

# paths./api/statement-sale-items/.get.parameters[].description
One or more ISRCs, separated by commas. Required unless `upc` is given.

# paths./api/statement-sale-items/.get.parameters[].description
A page number within the paginated result set.

# paths./api/statement-sale-items/.get.parameters[].description
A reporting-period code, for example 2024-04. Omit for every period.

# paths./api/statement-sale-items/.get.parameters[].description
Limit the rows to one royalty statement.

# paths./api/statement-sale-items/.get.parameters[].description
One or more UPCs, separated by commas. Required unless `isrc` is given.

# paths./api/statement-sale-items/download/.get.description
Streams the same rows as `list`, as a CSV attachment. The row count is capped; a response carrying exactly the cap in `X-Habitat-Max-Rows` means the results were truncated, so narrow the filters and ask again.

Requires the `statements:read` scope.

# paths./api/statement-sale-items/download/.get.summary
Download the matching statement sale items as CSV

# paths./api/statement-sale-items/download/.get.parameters[].description
One or more ISRCs, separated by commas. Required unless `upc` is given.

# paths./api/statement-sale-items/download/.get.parameters[].description
A reporting-period code, for example 2024-04. Omit for every period.

# paths./api/statement-sale-items/download/.get.parameters[].description
Limit the rows to one royalty statement.

# paths./api/statement-sale-items/download/.get.parameters[].description
One or more UPCs, separated by commas. Required unless `isrc` is given.

# paths./api/stores/.get.description
List stores available for the team (based on their uploaded data).

Requires the `revenue_streams:read` scope.

# paths./api/stores/.get.parameters[].description
A page number within the paginated result set.

# paths./api/stores/{id}/.get.description
List stores available for the team (based on their uploaded data).

Requires the `revenue_streams:read` scope.

# paths./api/stores/{id}/.get.parameters[].description
A unique integer value identifying this store.

# paths./api/track-dsp-earnings/.get.description
Catalog-level per-DSP, per-track royalty earnings keyed directly on ISRC/UPC.

``GET /api/track-dsp-earnings/?isrc={a,b}&upc={c,d}[&period={code}][&display_currency={XXX}]``

Returns one row per (source, reporting period, transaction period, DSP, usage type,
track) of gross recordings earnings taken straight from
``RecordingsIntermediateProcessedRoyaltyData`` — the catalog totals, with NO
deal-share / payee routing. This complements ``/api/payee-track-dsp-earnings/``
(which slices the same numbers by a single payee's deal shares).

- ``isrc`` and/or ``upc`` (at least one required): comma-separated codes; matching is
  case-insensitive and tokens are trimmed. Multiple tracks may be requested at once.
- ``period`` (optional): a reporting-period code (e.g. ``2024-04``); omit for lifetime.
- ``display_currency`` (optional): a 3-letter currency code (e.g. ``INR``). Catalog
  earnings have no payee, so there is no payee preference to read — the target is
  explicit. Adds the additive ``origin_currency`` / ``converted_currency`` /
  ``exchange_rate`` / ``is_converted`` / ``converted_gross_revenue`` fields at an
  approximate daily rate (a period request converts at the period's financial date).
  On a rate cache miss ``exchange_rate`` is ``null``, ``is_converted`` is ``false``
  and amounts stay in the base currency.

Amounts are in the team's base currency. ISRC/UPC resolution is team-scoped: a code
owned by another team resolves to nothing and behaves exactly like an unknown code.

Requires the `statements:read` scope.

# paths./api/track-dsp-earnings/.get.parameters[].description
A page number within the paginated result set.

# paths./api/tracks/.get.parameters[].description
A page number within the paginated result set.

# paths./api/tracks/{id}/.get.parameters[].description
A unique integer value identifying this track.

# paths./api/tracks/{id}/.put.parameters[].description
A unique integer value identifying this track.

# paths./api/tracks/{id}/.patch.parameters[].description
A unique integer value identifying this track.

# paths./api/tracks/{id}/.delete.parameters[].description
A unique integer value identifying this track.

# paths./api/tracks/incomplete/.get.description
List tracks that have no ISRC rows.

Requires the `content:read` scope.

# components.schemas.AddMerchItemsToDealRequest.properties.merch_item_ids.description
The merch items to act on. Must not be empty.

# components.schemas.AddRecordsToDealRequest.properties.track_ids.description
The tracks to act on. Must not be empty.

# components.schemas.AddSplitRequest.description
Serializer for the new add-split action supporting territory/store/usage type combinations.

# components.schemas.ArtistTypeEnum.description
* `main_artist` - Main Artist
* `featured_artist` - Featured Artist
* `remixer` - Remixer
* `producer` - Producer
* `composer` - Composer
* `lyricist` - Lyricist

# components.schemas.CompositionEarningsTypeEnum.description
* `general` - General
* `mechanical` - Mechanical
* `public_performance_total` - Public Performance - Total
* `public_performance_publisher` - Public Performance - Publisher Share
* `synchronization` - Synchronization
* `print` - Print
* `other` - Other

# components.schemas.ConfigureAdvancedDealRequest.properties.specific_territories.description
Country codes mapped to whether the deal covers them, for example {"US": true, "GB": false}.

# components.schemas.CurrencyEnum.description
* `USD` - USD
* `EUR` - EUR
* `GBP` - GBP
* `CAD` - CAD
* `AED` - AED
* `ARS` - ARS
* `AUD` - AUD
* `CHF` - CHF
* `CLP` - CLP
* `DKK` - DKK
* `HKD` - HKD
* `ILS` - ILS
* `INR` - INR
* `JPY` - JPY
* `KRW` - KRW
* `MXN` - MXN
* `MYR` - MYR
* `NOK` - NOK
* `NZD` - NZD
* `PHP` - PHP
* `PLN` - PLN
* `SEK` - SEK
* `SGD` - SGD
* `THB` - THB
* `TRY` - TRY
* `UYU` - UYU
* `ZAR` - ZAR
* `BRL` - BRL

# components.schemas.Deal.properties.payees.description
Payees on the deal and the share each one takes. Some keys depend on the deal type: a recordings deal adds territory, usage_type, stores and store_scoped; a compositions deal adds territory_set instead. The list is empty when the deal has no shares, or when the shares could not be read.

# components.schemas.Deal.properties.payees.items.properties.stores.description
Store names the share is limited to. Null when the share is not store-scoped, which is the common case.

# components.schemas.Deal.properties.deal_details.description
Terms of the deal. Which keys appear depends on the deal type: a recordings deal carries deal_kind and ownership_type, a merch deal does not, and a compositions deal returns null.

# components.schemas.Deal.properties.composition_splits.description
Composition splits held by the team, for reference. Null unless this is a compositions deal.

# components.schemas.DealKindEnum.description
* `Artist` - Artist
* `Label` - Label
* `Distribution` - Distribution

# components.schemas.DealTypeEnum.description
* `recordings` - recordings
* `compositions` - compositions
* `merch` - merch

# components.schemas.DefaultUsageTypeEnum.description
* `streaming` - Streaming
* `download` - Download
* `fingerprint` - Fingerprint
* `content_production` - Content Production
* `video` - Video
* `in-store` - In-Store
* `radio` - Radio
* `sync` - Sync
* `licensing` - Licensing
* `performance` - Neighboring Rights
* `physical` - Physical
* `other` - Other
* `unknown` - Unknown

# components.schemas.LegacyRecord.description
Deprecated: use TrackSerializer via /api/tracks/ instead.
Accepts both record_title and track_title for backwards compatibility.
Always returns record_title in responses.

# components.schemas.LegacyRecordRequest.description
Deprecated: use TrackSerializer via /api/tracks/ instead.
Accepts both record_title and track_title for backwards compatibility.
Always returns record_title in responses.

# components.schemas.MerchItemTypeEnum.description
* `vinyl` - Vinyl
* `cd` - CD
* `poster` - Poster
* `apparel` - Apparel
* `bundle` - Bundle
* `cassette` - Cassette
* `accessories` - Accessories
* `other` - Other

# components.schemas.OneOffIncomeComposition.description
Upgrade the reporting_period required/null error with the period-gap message.

Each one-off income serializer requires ``reporting_period`` through
``extra_kwargs``, so the field layer enforces the rule and OPTIONS
metadata reports the field as required. A row with no reporting period
never reaches payee earnings: both earnings flows join one-off income
to royalties_reportingperiod. This mixin only improves the message.
When the team has no period covering the entry date, the error names
the missing period instead of the bare required-field text.

Partial updates that do not send ``reporting_period`` stay allowed.
Legacy rows with a NULL period must remain editable; a periodless
write cannot slip through, because DRF skips a required check under
``partial=True`` only when the field is absent from the request.

# components.schemas.OneOffIncomeCompositionRequest.description
Upgrade the reporting_period required/null error with the period-gap message.

Each one-off income serializer requires ``reporting_period`` through
``extra_kwargs``, so the field layer enforces the rule and OPTIONS
metadata reports the field as required. A row with no reporting period
never reaches payee earnings: both earnings flows join one-off income
to royalties_reportingperiod. This mixin only improves the message.
When the team has no period covering the entry date, the error names
the missing period instead of the bare required-field text.

Partial updates that do not send ``reporting_period`` stay allowed.
Legacy rows with a NULL period must remain editable; a periodless
write cannot slip through, because DRF skips a required check under
``partial=True`` only when the field is absent from the request.

# components.schemas.OneOffIncomeMaster.description
Upgrade the reporting_period required/null error with the period-gap message.

Each one-off income serializer requires ``reporting_period`` through
``extra_kwargs``, so the field layer enforces the rule and OPTIONS
metadata reports the field as required. A row with no reporting period
never reaches payee earnings: both earnings flows join one-off income
to royalties_reportingperiod. This mixin only improves the message.
When the team has no period covering the entry date, the error names
the missing period instead of the bare required-field text.

Partial updates that do not send ``reporting_period`` stay allowed.
Legacy rows with a NULL period must remain editable; a periodless
write cannot slip through, because DRF skips a required check under
``partial=True`` only when the field is absent from the request.

# components.schemas.OneOffIncomeMasterRequest.description
Upgrade the reporting_period required/null error with the period-gap message.

Each one-off income serializer requires ``reporting_period`` through
``extra_kwargs``, so the field layer enforces the rule and OPTIONS
metadata reports the field as required. A row with no reporting period
never reaches payee earnings: both earnings flows join one-off income
to royalties_reportingperiod. This mixin only improves the message.
When the team has no period covering the entry date, the error names
the missing period instead of the bare required-field text.

Partial updates that do not send ``reporting_period`` stay allowed.
Legacy rows with a NULL period must remain editable; a periodless
write cannot slip through, because DRF skips a required check under
``partial=True`` only when the field is absent from the request.

# components.schemas.OneOffIncomeMerch.description
Upgrade the reporting_period required/null error with the period-gap message.

Each one-off income serializer requires ``reporting_period`` through
``extra_kwargs``, so the field layer enforces the rule and OPTIONS
metadata reports the field as required. A row with no reporting period
never reaches payee earnings: both earnings flows join one-off income
to royalties_reportingperiod. This mixin only improves the message.
When the team has no period covering the entry date, the error names
the missing period instead of the bare required-field text.

Partial updates that do not send ``reporting_period`` stay allowed.
Legacy rows with a NULL period must remain editable; a periodless
write cannot slip through, because DRF skips a required check under
``partial=True`` only when the field is absent from the request.

# components.schemas.OneOffIncomeMerchRequest.description
Upgrade the reporting_period required/null error with the period-gap message.

Each one-off income serializer requires ``reporting_period`` through
``extra_kwargs``, so the field layer enforces the rule and OPTIONS
metadata reports the field as required. A row with no reporting period
never reaches payee earnings: both earnings flows join one-off income
to royalties_reportingperiod. This mixin only improves the message.
When the team has no period covering the entry date, the error names
the missing period instead of the bare required-field text.

Partial updates that do not send ``reporting_period`` stay allowed.
Legacy rows with a NULL period must remain editable; a periodless
write cannot slip through, because DRF skips a required check under
``partial=True`` only when the field is absent from the request.

# components.schemas.OneOffIncomePayee.description
Upgrade the reporting_period required/null error with the period-gap message.

Each one-off income serializer requires ``reporting_period`` through
``extra_kwargs``, so the field layer enforces the rule and OPTIONS
metadata reports the field as required. A row with no reporting period
never reaches payee earnings: both earnings flows join one-off income
to royalties_reportingperiod. This mixin only improves the message.
When the team has no period covering the entry date, the error names
the missing period instead of the bare required-field text.

Partial updates that do not send ``reporting_period`` stay allowed.
Legacy rows with a NULL period must remain editable; a periodless
write cannot slip through, because DRF skips a required check under
``partial=True`` only when the field is absent from the request.

# components.schemas.OneOffIncomePayeeRequest.description
Upgrade the reporting_period required/null error with the period-gap message.

Each one-off income serializer requires ``reporting_period`` through
``extra_kwargs``, so the field layer enforces the rule and OPTIONS
metadata reports the field as required. A row with no reporting period
never reaches payee earnings: both earnings flows join one-off income
to royalties_reportingperiod. This mixin only improves the message.
When the team has no period covering the entry date, the error names
the missing period instead of the bare required-field text.

Partial updates that do not send ``reporting_period`` stay allowed.
Legacy rows with a NULL period must remain editable; a periodless
write cannot slip through, because DRF skips a required check under
``partial=True`` only when the field is absent from the request.

# components.schemas.OwnershipTypeEnum.description
* `Original Author` - Original Author
* `Copyright Transfer` - Copyright Transfer
* `License` - License
* `Sub-License` - Sub-License

# components.schemas.PatchedLegacyRecordRequest.description
Deprecated: use TrackSerializer via /api/tracks/ instead.
Accepts both record_title and track_title for backwards compatibility.
Always returns record_title in responses.

# components.schemas.PatchedOneOffIncomeCompositionRequest.description
Upgrade the reporting_period required/null error with the period-gap message.

Each one-off income serializer requires ``reporting_period`` through
``extra_kwargs``, so the field layer enforces the rule and OPTIONS
metadata reports the field as required. A row with no reporting period
never reaches payee earnings: both earnings flows join one-off income
to royalties_reportingperiod. This mixin only improves the message.
When the team has no period covering the entry date, the error names
the missing period instead of the bare required-field text.

Partial updates that do not send ``reporting_period`` stay allowed.
Legacy rows with a NULL period must remain editable; a periodless
write cannot slip through, because DRF skips a required check under
``partial=True`` only when the field is absent from the request.

# components.schemas.PatchedOneOffIncomeMasterRequest.description
Upgrade the reporting_period required/null error with the period-gap message.

Each one-off income serializer requires ``reporting_period`` through
``extra_kwargs``, so the field layer enforces the rule and OPTIONS
metadata reports the field as required. A row with no reporting period
never reaches payee earnings: both earnings flows join one-off income
to royalties_reportingperiod. This mixin only improves the message.
When the team has no period covering the entry date, the error names
the missing period instead of the bare required-field text.

Partial updates that do not send ``reporting_period`` stay allowed.
Legacy rows with a NULL period must remain editable; a periodless
write cannot slip through, because DRF skips a required check under
``partial=True`` only when the field is absent from the request.

# components.schemas.PatchedOneOffIncomeMerchRequest.description
Upgrade the reporting_period required/null error with the period-gap message.

Each one-off income serializer requires ``reporting_period`` through
``extra_kwargs``, so the field layer enforces the rule and OPTIONS
metadata reports the field as required. A row with no reporting period
never reaches payee earnings: both earnings flows join one-off income
to royalties_reportingperiod. This mixin only improves the message.
When the team has no period covering the entry date, the error names
the missing period instead of the bare required-field text.

Partial updates that do not send ``reporting_period`` stay allowed.
Legacy rows with a NULL period must remain editable; a periodless
write cannot slip through, because DRF skips a required check under
``partial=True`` only when the field is absent from the request.

# components.schemas.PatchedOneOffIncomePayeeRequest.description
Upgrade the reporting_period required/null error with the period-gap message.

Each one-off income serializer requires ``reporting_period`` through
``extra_kwargs``, so the field layer enforces the rule and OPTIONS
metadata reports the field as required. A row with no reporting period
never reaches payee earnings: both earnings flows join one-off income
to royalties_reportingperiod. This mixin only improves the message.
When the team has no period covering the entry date, the error names
the missing period instead of the bare required-field text.

Partial updates that do not send ``reporting_period`` stay allowed.
Legacy rows with a NULL period must remain editable; a periodless
write cannot slip through, because DRF skips a required check under
``partial=True`` only when the field is absent from the request.

# components.schemas.PatchedRevenueStreamRequest.description
Read-only for list/retrieve, only 'name' is updatable.

# components.schemas.PatchedSetDisplayCurrencyRequest.properties.display_currency.description
A three-letter currency code, or null to reset to the payee's base currency.

# components.schemas.PayeeRoleEnum.description
* `artist` - artist
* `label` - label
* `producer` - producer
* `publisher` - publisher
* `engineer` - engineer
* `distributor` - distributor
* `other` - other

# components.schemas.PayeeTrackDspEarnings.description
Read-only row for the per-DSP, per-track payee earnings breakdown.

Each row is one (source, reporting_period, transaction_period, store/DSP, usage_type,
track, deal) slice of a payee's recordings earnings, matching the payee's
period/lifetime statement (net_royalty = gross_revenue * deal share %).

``usage_type`` distinguishes streaming vs download so a consumer can present Streams
and Downloads separately; ``reporting_period`` plus ``period_start_date`` /
``period_end_date`` supply the "reported until" date range. ``store`` is the DSP.

Amounts stay in the payee's base currency (the team base). The display-currency
fields are **additive** (see :func:`_attach_display_conversion`): an approximate
daily rate to the payee's display currency, uniform for the whole response, with
pre-multiplied ``converted_gross_revenue`` / ``converted_net_royalty``. On a rate
cache miss ``exchange_rate`` is ``null`` and amounts stay in the base currency.

# components.schemas.Payment.properties.payment_period_details.description
The reporting period this payment belongs to. Null when the payment has no period.

# components.schemas.PaymentMethodEnum.description
* `PayPal` - PayPal
* `Bank Transfer` - Bank Transfer
* `Venmo` - Venmo
* `Zelle` - Zelle
* `Other` - Other

# components.schemas.ProEnum.description
* `AKM` - AKM
* `APRA` - APRA
* `ASCAP` - ASCAP
* `BMI` - BMI
* `BUMA` - BUMA
* `ECAD` - ECAD
* `GEMA` - GEMA
* `GMR` - GMR
* `IMRO` - IMRO
* `IRMA` - IRMA
* `JASRAC` - JASRAC
* `KOMCA` - KOMCA
* `MCPS` - MCPS
* `MCSC` - MCSC
* `MUSICAUTHOR` - MUSICAUTHOR
* `PRS` - PRS
* `RAO` - RAO
* `SABAM` - SABAM
* `SACEM` - SACEM
* `SACM` - SACM
* `SADAIC` - SADAIC
* `SCD` - SCD
* `SESAC` - SESAC
* `SGAE` - SGAE
* `SIAE` - SIAE
* `SOCAN` - SOCAN
* `STEMRA` - STEMRA
* `STIM` - STIM
* `SUISA` - SUISA
* `TEOSTO` - TEOSTO
* `TONO` - TONO
* `Other` - Other

# components.schemas.ProcessingStatusEnum.description
* `uploaded` - Uploaded
* `processing` - Processing
* `processed` - Processed
* `processing_failed` - Processing Failed
* `more_info_needed` - More Info Needed
* `manual_processing` - Manual Processing Required
* `deleting` - Deleting

# components.schemas.ProcessingTypeEnum.description
* `simple` - simple
* `complex` - complex

# components.schemas.ProductVersionEnum.description
* `lp` - LP (Album)
* `ep` - EP
* `single` - Single
* `compilation` - Compilation
* `remix_pack` - Remix Pack
* `vinyl` - Vinyl
* `cd` - CD
* `cassette` - Cassette
* `box_set` - Box Set
* `deluxe_edition` - Deluxe Edition
* `live` - Live
* `remaster` - Remaster
* `mixtape` - Mixtape
* `soundtrack` - Soundtrack
* `instrumental` - Instrumental

# components.schemas.ReportingCadenceEnum.description
* `Monthly` - Monthly
* `Quarterly` - Quarterly
* `Annually` - Annually
* `Biannually` - Biannually
* `Cumulative` - Cumulative
* `One-off` - One-off

# components.schemas.ReportingPeriodTypeEnum.description
* `Month` - Month
* `Quarter` - Quarter
* `Half` - Half
* `Year` - Year
* `Custom` - Custom

# components.schemas.RevenueStream.description
Read-only for list/retrieve, only 'name' is updatable.

# components.schemas.RevenueStreamRequest.description
Read-only for list/retrieve, only 'name' is updatable.

# components.schemas.RoyaltySourceEnum.description
* `ADA` - ADA
* `AGATA` - AGATA
* `Amazon Music` - Amazon Music
* `Americana Songs` - Americana Songs
* `Americana Songs [Physical]` - Americana Songs [Physical]
* `AMCOS` - AMCOS
* `AMRA` - AMRA
* `APRA` - APRA
* `ASCAP` - ASCAP
* `AWAL` - AWAL
* `Absoute Label Services` - Absoute Label Services
* `Audiomack` - Audiomack
* `AudioSalad` - AudioSalad
* `BMG Publishing` - BMG Publishing
* `BMI` - BMI
* `Bandcamp` - Bandcamp
* `Believe` - Believe
* `CD Baby` - CD Baby
* `Click n Clear` - Click n Clear
* `CMRRA` - CMRRA
* `Curve` - Curve
* `Curve [Publishing]` - Curve [Publishing]
* `DashGo` - DashGo
* `Digdis` - Digdis
* `Distrodirect` - Distrodirect
* `Distrokid` - Distrokid
* `Ditto` - Ditto
* `EMPIRE` - EMPIRE
* `FUGA` - FUGA
* `Foundation Media` - Foundation Media
* `Habitat` - Habitat
* `Habitat Custom [Merchandise]` - Habitat Custom [Merchandise]
* `Habitat Custom [Recordings]` - Habitat Custom [Recordings]
* `Harry Fox Agency` - Harry Fox Agency
* `IDOL` - IDOL
* `IFPI` - IFPI
* `IPF` - IPF
* `ILS` - ILS
* `internal_mechanicals` - Internal Mechanicals
* `Indie Pool` - Indie Pool
* `Ingrooves` - Ingrooves
* `Kobalt [Publishing]` - Kobalt [Publishing]
* `Kobalt [Recordings]` - Kobalt [Recordings]
* `Kontor New Media` - Kontor New Media
* `Label Engine` - Label Engine
* `Labelworx` - Labelworx
* `Lifted House` - Lifted House
* `Many Hats` - Many Hats
* `Matter` - Matter
* `MerchNow` - MerchNow
* `Merlin Anghami` - Merlin Anghami
* `Merlin Audiomack` - Merlin Audiomack
* `Merlin AWA` - Merlin AWA
* `Merlin Apple Music` - Merlin Apple Music
* `Merlin Boomplay` - Merlin Boomplay
* `Merlin Deezer` - Merlin Deezer
* `Merlin Flo` - Merlin Flo
* `Merlin IHeartRadio` - Merlin IHeartRadio
* `Merlin iTunes` - Merlin iTunes
* `Merlin JOOX` - Merlin JOOX
* `Merlin KKBox` - Merlin KKBox
* `Merlin Mixcloud` - Merlin Mixcloud
* `Merlin NetEase` - Merlin NetEase
* `Merlin Pandora` - Merlin Pandora
* `Merlin Resso` - Merlin Resso
* `Merlin Roxi` - Merlin Roxi
* `Merlin SberZvuk` - Merlin SberZvuk
* `Merlin Slacker` - Merlin Slacker
* `Merlin Snap` - Merlin Snap
* `Merlin Soundtrack Your Brand` - Merlin Soundtrack Your Brand
* `Merlin Spotify` - Merlin Spotify
* `Merlin Tencent` - Merlin Tencent
* `Merlin TikTok` - Merlin TikTok
* `Merlin Trebel` - Merlin Trebel
* `Merlin Yandex` - Merlin Yandex
* `Meta` - Meta
* `MCPS` - MCPS
* `MLC` - MLC
* `MOD` - MOD
* `MTN` - MTN
* `Music Bed` - Music Bed
* `MVD` - MVD
* `Nue Meta` - Nue Meta
* `Now Thats What I Call Music` - Now Thats What I Call Music
* `Open` - Open
* `OpenPlay` - OpenPlay
* `Paradise Worldwide` - Paradise Worldwide
* `PPCA` - PPCA
* `Platoon` - Platoon
* `PMI` - PMI
* `PPI` - PPI
* `PPL` - PPL
* `PRS` - PRS
* `Quattro Music` - Quattro Music
* `Revelator` - Revelator
* `Revolver Digital` - Revolver Digital
* `Revolver Physical` - Revolver Physical
* `Routenote` - Routenote
* `SESAC` - SESAC
* `Sentric` - Sentric
* `Sentric Neighboring Rights` - Sentric Neighboring Rights
* `Shopify` - Shopify
* `Simplecast` - Simplecast
* `Smoothnotes` - Smoothnotes
* `Soko Music` - Soko Music
* `Songtradr Pretzel` - Songtradr Pretzel
* `Spare Music` - Spare Music
* `Sony Music` - Sony Music
* `SoundExchange` - SoundExchange
* `Soundcloud` - Soundcloud
* `Source Audio` - Source Audio
* `State 51` - State 51
* `STIM` - STIM
* `Symphonic` - Symphonic
* `SyncVault` - SyncVault
* `The Flenser` - The Flenser
* `The Orchard` - The Orchard
* `The Rest Is Noise` - The Rest Is Noise
* `Think Indie` - Think Indie
* `TikTok` - TikTok
* `Too Lost` - Too Lost
* `Tracklib Recordings` - Tracklib Recordings
* `Tracklib Publishing` - Tracklib Publishing
* `Tunecore` - Tunecore
* `UMA` - UMA
* `Unison` - Unison
* `Universal Music Group` - Universal Music Group
* `Virgin Music Group` - Virgin Music Group
* `Vydia` - Vydia
* `Warner Music` - Warner Music
* `Warner Music France` - Warner Music France
* `Wiseband` - Wiseband
* `Wix` - Wix
* `X5 Music Group` - X5 Music Group
* `Xelon` - Xelon / Noisehive
* `YouTube` - YouTube
* `Zebralution` - Zebralution
* `ABRAMS` - ABRAMS
* `Addictech Records` - Addictech Records
* `AGEDI` - AGEDI
* `Alliance Entertainment` - Alliance Entertainment
* `Alpha Pup Records` - Alpha Pup Records
* `Cherry Red Records` - Cherry Red Records
* `Cherry Red Records [Custom]` - Cherry Red Records [Custom]
* `Cataloghi` - Cataloghi
* `GVL` - GVL
* `Shivelight` - Shivelight
* `Lasgo` - Lasgo
* `Little Amber Fish` - Little Amber Fish
* `LSG` - LSG
* `Prime Direct` - Prime Direct
* `Platinum Music` - Platinum Music
* `Power Station Music` - Power Station Music
* `Re:Sound` - Re:Sound
* `SIMIN` - SIMIN
* `SENA` - SENA
* `SCF` - SCF
* `Shout Factory` - Shout Factory
* `Shinko Music` - Shinko Music
* `Shinko Music [Merchandise]` - Shinko Music [Merchandise]
* `S2S Japan` - S2S Japan
* `MAHASZ` - MAHASZ
* `Westside Enterprises` - Westside Enterprises
* `One Media` - One Media
* `OneRPM` - OneRPM
* `Miles Away Records` - Miles Away Records
* `Omnivore` - Omnivore
* `Strictly Confidential` - Strictly Confidential
* `NCB` - NCB
* `Other` - Other

# components.schemas.RoyaltyStatement.properties.revenue_stream_details.description
The revenue stream this statement belongs to. Null when the statement has none.

# components.schemas.RoyaltyStatementMinimal.description
Minimal serializer for royalty statement lookup responses.

# components.schemas.RoyaltyStatementMinimal.properties.revenue_stream_details.description
The revenue stream this statement belongs to. Null when the statement has none.

# components.schemas.RoyaltyTypeEnum.description
* `recordings` - Recordings
* `publishing` - Publishing
* `nr` - Neighboring Rights
* `merchandise` - Merchandise

# components.schemas.SourceTypeEnum.description
* `Recordings` - Recordings
* `Compositions` - Compositions
* `Merchandise` - Merchandise

# components.schemas.StatementSaleItem.description
One raw sale line as it was ingested from a royalty statement file.

These are ``ProcessedRoyaltydata`` rows: the per-row contents of the uploaded
statement after Habitat has parsed and standardised it, with no deal-share or
payee routing applied. Values prefixed ``raw_`` are what the source reported;
the unprefixed twin is Habitat's standardised version.

``statement_id`` / ``statement_name`` / ``statement_source`` identify the file the
row came from, so every line traces back to an upload.

# components.schemas.TrackDspEarnings.description
Read-only row for the catalog-level per-DSP, per-track earnings breakdown.

Each row is one (source, reporting_period, transaction_period, store/DSP, usage_type,
track) slice of gross recordings earnings taken directly from
``RecordingsIntermediateProcessedRoyaltyData`` — the catalog totals, with no
deal-share or payee routing. ``usage_type`` distinguishes streaming vs download;
``reporting_period`` plus ``period_start_date`` / ``period_end_date`` supply the
"reported until" date range; ``store`` is the DSP.

Amounts are in the team's base currency. The display-currency fields are **additive**
(see :func:`_attach_display_conversion`): an approximate daily rate to the currency
requested via the ``display_currency`` query param (catalog earnings have no payee,
so there is no payee preference to read), uniform for the whole response, with a
pre-multiplied ``converted_gross_revenue``. On a rate cache miss ``exchange_rate``
is ``null`` and amounts stay in the base currency.

# components.schemas.UsageTypeEnum.description
* `general` - General
* `streaming` - Streaming
* `download` - Download
* `fingerprint` - Fingerprint
* `content_production` - Content Production
* `video` - Video
* `in-store` - In-Store
* `radio` - Radio
* `publishing` - Publishing
* `sync` - Sync
* `licensing` - Licensing
* `performance` - Neighboring Rights
* `physical` - Physical
* `merchandise` - Merchandise
* `other` - Other
* `single_compilation` - Single Rate (In House Comp)
* `album_compilation` - Album Rate  (In House Comp)
* `digital_unbundled` - Digital Unbundled
* `digital_bundled` - Digital Bundled
* `third_party_rate` - 3rd Party Rate
* `third_party_os_rate` - 3rd Party Overseas Rate
* `reserve` - Reserve
* `publishing_rate` - Publishing Rate
* `packaging` - Packaging
* `youtube` - YouTube

# components.securitySchemes.TeamToken.description
Team API token. Send the header `Authorization: Token habitatkey_<token>`.

Create a token in the Habitat app under Settings, then API. The raw token is shown once, at creation.

A token expires 90 days after it is issued and can be revoked at any time. It reads and writes the data of exactly one team.

**Scopes.** A token carries a list of scopes, and each scope names one module and one verb — for example `payees:read` or `deals:write`. `<module>:write` also grants `<module>:read`. Every operation below states the scope it needs in `x-required-scope`. A request outside a token's scopes is refused with 403 and a `WWW-Authenticate` header naming the missing scope.

The full list is published at `/.well-known/oauth-protected-resource` (RFC 9728). It is: `content:read`, `content:write`, `deals:read`, `deals:write`, `payees:read`, `payees:write`, `payments:read`, `payments:write`, `expenses:read`, `expenses:write`, `statements:read`, `statements:write`, `revenue_streams:read`, `revenue_streams:write`.