# Dashboard Tour (/dashboard) The sidebar is grouped by what you are trying to do, not by how the system is built. This page is the map. Some entries only appear once an add-on is active or your role includes the matching permission. ## Overview [#overview] | Area | What it is for | | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | | **Dashboard** | Your landing page. Catalog volume, revenue, and recent activity at a glance. | | **Users** | Your customer accounts: artists and labels who registered on your portal. Open one to see their catalog, subscription, and account history. | Users are your customers. Your own staff live under **Members**, further down. ## Catalog [#catalog] Everything your customers create, and the gate it passes through before distribution. | Area | What it is for | | ------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Releases** | Every release in your platform, with status, release date, and owner. | | **Tracks** | Track-level view across the catalog, useful for finding missing ISRCs. | | **Artists** | Artist profiles, including the store profile links used at delivery. | | **Labels** | Label records. Releases fall back to your default label name when none is set. | | **Review & Delivery > Release Queue** | The review workspace, one level down under Review & Delivery. Releases your customers submitted, waiting for your decision. Needs the `process releases` permission. | ### How a release actually moves [#how-a-release-actually-moves] **Your customer builds it.** They create the release, upload audio and artwork, add metadata and contributors, then submit. **It lands in your Release Queue.** Your team opens it, works through the QC findings the system flagged, and checks the release-level blockers. **You decide.** Approve it, request changes, or ask for rights documentation. Requesting changes sends it back to the customer with your notes. **It goes out.** Approved releases enter distribution and pick up a delivery status you can track per release. Delivery status meanings are documented in [Delivery Statuses](/delivery-api/delivery-statuses). Metadata rules that cause the most rejections are in the [Metadata Style Guide](/delivery-api/metadata-style-guide). ## Finance [#finance] | Area | What it is for | | ----------- | -------------------------------------------------------------------------------- | | **Sales** | Imported sales and streaming revenue, broken down by release, store, and period. | | **Splits** | Revenue split agreements between rights holders on a release. | | **Payouts** | Payout requests from your customers, and the queue your finance team processes. | Your customers add their own payout method under their **Account Settings**, either a PayPal address or bank details. ## Operations [#operations] | Area | What it is for | Needs | | -------------------- | ------------------------------------------------------------------------------------------ | ---------------------------------------------------- | | **Activity Log** | Audit trail of who changed what and when. | `view logs` permission | | **Copyrights** | Copyright match results on submitted tracks, plus the credit balance that pays for checks. | Copyright checks enabled | | **Tickets** | Support requests from your customers, with owner and status. | [Support Desk Manager](/addons/support-desk-manager) | | **Ticket Dashboard** | Volume, response, and resolution reporting across tickets. | [Support Desk Manager](/addons/support-desk-manager) | | **Smartlinks** | Branded release landing pages and their click analytics. | [Smartlinks](/addons/release-smartlinks) | ### Copyright credits in one paragraph [#copyright-credits-in-one-paragraph] Copyright checking runs on credits. You top the balance up from the Copyrights area, credits are added instantly after payment, and larger top-ups carry a bonus percentage. Tracks with a match appear as copyright issues on the release, where your customer can submit rights documentation and your team can approve or reject it. Credits reserved against an open check show as on hold until it resolves. ## Settings [#settings] | Area | What it is for | Needs | | ------------------------------------------------- | ----------------------------------------------------------------------------------- | ---------------------------------------------------------- | | **[Brand Settings](/branding/overview)** | Your brand, languages, payments, domain, email, support, SSO, and legal pages. | Admin access | | **[Upgrades](/branding/payment#what-you-sell)** | Membership plans and pay-per-release pricing you sell to customers. | `manage membershippackages` | | **[Addons](/addons/overview)** | The add-on store: browse, install, activate, deactivate. | Admin access | | **[Members](/addons/members-management)** | Your internal staff, their roles, and their permissions. | [Team Members](/addons/members-management) | | **[Theme Editor](/addons/theme-editor)** | Dashboard colors, fonts, spacing, and layout. | [Theme Editor](/addons/theme-editor) | | **[Email Theme](/addons/email-theme-customizer)** | Branded design for outbound platform emails. | [Email Theme Customizer](/addons/email-theme-customizer) | | **DDEX Gateway** | Partner connections and your Delivery API credentials. | [Enterprise Delivery API](/addons/enterprise-delivery-api) | | **Account Settings** | Your own profile, password, two-factor authentication, sessions, and notifications. | Everyone | ## Where do I go to... [#where-do-i-go-to] | Task | Go to | | --------------------------------- | ------------------------------------------------- | | Approve a release | Catalog > Review & Delivery > Release Queue | | See why a release was flagged | Release Queue, open the release, read QC findings | | Change your logo or brand name | Settings > Brand Settings > General Settings | | Change your prices | Settings > Upgrades | | Add a staff member | Settings > Members | | Look up a customer | Overview > Users | | Find out who deleted something | Operations > Activity Log | | Create API credentials | Settings > DDEX Gateway > API access | | Turn on two-factor authentication | Settings > Account Settings |
Missing a sidebar entry?

Two things hide an area: the add-on that provides it is not active, or your role does not include the matching permission. Deactivating an add-on removes its sidebar entry and blocks direct page access, but keeps the data so nothing is lost if you reactivate it later.

## Next [#next] # Getting Started (/gettingstarted) This is the setup order that works. Each step unlocks the next, so skipping ahead usually means redoing work. Everything below happens in **Settings > Brand Settings** unless stated otherwise. ## Step 1: Start your trial [#step-1-start-your-trial] New organizations open in demo mode. You can look around and edit your brand name, logo, and languages right away, but the sections that make the portal live are locked. Authorize a card to start the **30-day free trial**. Nothing is charged that day. This unlocks payments, domain setup, email setup, support settings, SSO, and your legal pages.
Locked while in demo mode

Payment Options, Domain Setup, Email Setup, Support Settings, all three SSO sections, Terms of Services, and Privacy Policy stay read-only until the trial is started, and releases cannot be submitted . General Settings and Languages are editable from day one, so you can prepare your branding first.

## Step 2: Brand the portal [#step-2-brand-the-portal] Open **General Settings** and set your brand name, upload your logo, pick your commercial currency, and set the default label name. Turn on only the toggles you are ready to support. Then open **Languages** and enable the languages your customers actually need. Everything is included at no extra cost. Full detail: [General Settings](/branding/branding) and [Languages](/branding/languages). ## Step 3: Connect your domain [#step-3-connect-your-domain] This is the step with the longest waiting time, so start it early. 1. Open **Domain Setup**, enter your domain, and save. A TXT ownership record appears. 2. Publish that TXT record at your DNS provider, wait for propagation, then select **Verify ownership**. 3. Publish the CNAME record shown in step 3 of the page. The dashboard checks DNS automatically and switches you over once the record is live and the certificate is ready. Your default workspace domain keeps working the whole time. Full detail: [Domain Setup](/branding/domain). ## Step 4: Set up sender email [#step-4-set-up-sender-email] Email Setup needs a connected custom domain first, so do this after step 3. Set your sender name and an address on your domain, such as `noreply@yourlabel.com`, then publish the authentication TXT records the page generates. Until authentication completes, platform emails still send from a neutral fallback address rather than yours. Full detail: [Email Setup](/branding/email). ## Step 5: Take payments [#step-5-take-payments] Open **Payment Options** and connect Stripe, PayPal, or Airwallex with your own account credentials. Activate a gateway, then decide whether it also handles recurring memberships. Then open **Settings > Upgrades** to define what you actually sell: membership plans and pay-per-release pricing. Run one small real transaction end to end before you announce anything. Full detail: [Payment Options](/branding/payment). ## Step 6: Publish support and legal content [#step-6-publish-support-and-legal-content] | Section | Why it blocks launch | | ------------------------------------- | ---------------------------------------------------------------------- | | [Support Settings](/branding/support) | Your customers need a working way to reach you from inside the portal. | | [Terms of Services](/branding/terms) | Referenced from registration and checkout. | | [Privacy Policy](/branding/privacy) | Required before you collect registrations or payment details. | ## Step 7: Add your team and extensions [#step-7-add-your-team-and-extensions] Install the free [Team Members](/addons/members-management) add-on and invite staff with the narrowest role preset that fits their job. Then browse [Add-ons](/addons/overview) for anything else you need, such as [Smartlinks](/addons/release-smartlinks) for release campaigns or [Support Desk Manager](/addons/support-desk-manager) for ticketing. If you are connecting your own systems, the [Enterprise Delivery API](/addons/enterprise-delivery-api) add-on unlocks API credentials under **Settings > DDEX Gateway**. ## Pre-launch checklist [#pre-launch-checklist] Run through this in a private browser window before you send the first customer link. * [ ] Custom domain loads over HTTPS and shows your branding * [ ] Registration and login both work on the custom domain * [ ] A test email arrives from your own sender address, not the fallback * [ ] One real checkout completes and appears in your gateway dashboard * [ ] Terms and privacy pages open from registration and checkout * [ ] Support email is monitored by someone * [ ] A test release moves through the review queue as expected * [ ] Each team member sees only the areas their role allows ## If something goes wrong [#if-something-goes-wrong] Roll back one thing at a time, not everything at once. Your default workspace domain, your previous DNS records, and your previous gateway configuration should stay available until launch is accepted. | Problem | First thing to check | | ------------------------------------ | ------------------------------------------------------------------------------ | | Custom domain not resolving | The CNAME target matches exactly and no conflicting A or AAAA records exist | | Emails arrive from the wrong address | Domain authentication finished, and the sender is on your registrable domain | | Checkout fails | Gateway credentials are for the right environment and the gateway is activated | | A team member cannot see a page | Their role preset, then whether the related add-on is active | ## Next [#next] # SpaceMedia Enterprise Docs (/) SpaceMedia Enterprise is a white-label music distribution platform. You get a branded dashboard on your own domain where your artists and label clients manage releases, and where your team handles review, delivery, revenue splits, payouts, and support. These guides cover the dashboard. The [Delivery API](/delivery-api) and [Reports API](/reports-api) references cover the integration surface. ## Where to start [#where-to-start] | You are | Start here | Then read | | -------------------- | ------------------------------------------ | ---------------------------------------------- | | New platform owner | [Getting Started](/gettingstarted) | [Brand Settings](/branding/overview) | | Daily operator | [Dashboard Tour](/dashboard) | [Add-ons](/addons/overview) | | Setting up your team | [Team Members](/addons/members-management) | [Support Settings](/branding/support) | | Developer | [Quickstart](/delivery-api/api-quickstart) | [Authentication](/delivery-api/authentication) | | Reporting team | [Reports API](/reports-api) | [Authentication](/reports-api/authentication) | ## The three layers [#the-three-layers] **Your brand.** Your logo, colors, domain, sender email, languages, legal pages, and support details. Configured in [Brand Settings](/branding/overview). **Your catalog.** Artists, labels, releases, and tracks, plus the review queue your team uses before anything is distributed. See the [Dashboard Tour](/dashboard). **Your extensions.** Optional [add-ons](/addons/overview) for team access, smartlinks, theming, help center, ticketing, and API access. Install only what you need.
Everything is scoped to your organization

Your dashboard, your API credentials, and your data are isolated from every other SpaceMedia organization. Team roles and permissions apply identically in the dashboard and over the API, so an integration can never do more than the credential it uses is allowed to do.

## Machine-readable sources [#machine-readable-sources] The API references are generated from validated OpenAPI contracts. Use the [Delivery API contract](/delivery-api/openapi.json) or [Reports API contract](/reports-api/openapi.json) for SDK generation, and [llms.txt](/llms.txt) or [llms-full.txt](/llms-full.txt) if you are feeding these docs to an AI assistant. # What SpaceMedia Enterprise Is (/introduction) SpaceMedia Enterprise gives you a music distribution business without building the software. You run the brand, set the prices, and own the customer relationship. We run the platform, the delivery pipeline to stores, and the reporting. ## What you get [#what-you-get] | | | | -------------------- | ----------------------------------------------------------------------------------------------------------------- | | **A branded portal** | Your logo, your colors, your domain, your sender email. Your customers never see SpaceMedia. | | **A catalog system** | Artists, labels, releases, and tracks with metadata validation built in. | | **A review layer** | A queue where your team approves or rejects releases before they leave the platform. | | **Distribution** | Delivery to stores and streaming services, with status tracking per release. | | **Money handling** | Your own payment gateway, your membership and pay-per-release pricing, revenue splits, and payouts. | | **Extensions** | Optional [add-ons](/addons/overview) for team roles, smartlinks, theming, help center, ticketing, and API access. | ## Who works inside it [#who-works-inside-it] | Role | What they do | | --------------------------- | -------------------------------------------------------------------------------------------------------------------------- | | **You, the platform owner** | Configure the brand, pricing, payments, and legal pages. Full access to every area. | | **Your team** | Staff you invite with a role that limits them to the areas they need. Requires [Team Members](/addons/members-management). | | **Your customers** | Artists and labels who register on your portal, create releases, and submit them for review. | | **Your integrations** | Systems you connect using API credentials. Requires the [Enterprise Delivery API](/addons/enterprise-delivery-api) add-on. | ## Where the line sits [#where-the-line-sits] **You control:** branding, domain, sender email, languages, pricing, payment gateways, legal content, support contacts, which add-ons are active, who is on your team, and which releases pass review. **We handle:** hosting, TLS certificates, the delivery pipeline to stores, sales report ingestion, platform security, and platform updates.
You are not sharing an account with anyone

Each SpaceMedia Enterprise organization is fully isolated. Your customers, catalog, revenue data, credentials, and settings are only visible inside your own organization, and API credentials you create cannot read or write anything outside it.

## What the docs cover [#what-the-docs-cover] * **[Dashboard Tour](/dashboard)** walks the sidebar so you know where everything lives. * **[Getting Started](/gettingstarted)** is the setup order for a new platform. * **[Brand Settings](/branding/overview)** documents every configuration section, one page per section. * **[Add-ons](/addons/overview)** documents each optional capability and how it is billed. * **[Delivery API](/delivery-api)** and **[Reports API](/reports-api)** are for developers. ## Common questions [#common-questions] **Do my customers know SpaceMedia is behind the platform?** No. On a connected custom domain with your branding and sender email configured, the portal is entirely yours. **Can I set my own prices?** Yes. Memberships and pay-per-release pricing are yours to define, and payments go through your own gateway account. **Do I need a developer?** No. Everything in these guides is done through the dashboard. The API is optional and sold as a separate add-on. **How do I give my own staff dashboard access?** Install the free [Team Members](/addons/members-management) add-on, then invite each person with a role preset that matches their job. Staff accounts are separate from your customer accounts. # Delivery API Changelog (/changelog/delivery-api) The Delivery API changelog records endpoint, schema, webhook, validation, authentication, and behavior changes. Each entry states the affected operations and required integration action. # Changelogs (/changelog) SpaceMedia publishes the Whitelabel changelog first, followed by separate Delivery API and Reports API histories for technical integration changes. # Reports API Changelog (/changelog/reports-api) The Reports API changelog records reporting, analytics, export, reconciliation, dispute, payout, and financial-data contract changes. Each entry states availability and required integration action. # Whitelabel Changelog (/changelog/whitelabel) The Whitelabel changelog is a detailed weekly release digest for organization owners, administrators, operations, and support teams. Each entry separates shipped product changes from their operational impact. # Acting for Users (/delivery-api/acting-for-users) Catalog endpoints accept `X-User-Id` so a trusted organization integration can perform an allowed artist, release, track, or split action for a user in the same organization. On catalog **writes and uploads the header is mandatory**, not optional. Send it and the request is attributed to that user; omit it and the API returns `403` with `A public acting-user reference is required for write operations.` On catalog reads the header is optional and narrows results to what that user can see. ## When to use it [#when-to-use-it] | Scenario | Use `X-User-Id` | | ------------------------------------------------------------------------ | --------------- | | A label operations tool creates releases for an artist account | Yes | | A catalog import maps tracks to the uploader who owns the artist profile | Yes | | A billing integration manages organization payment methods | No | | A cross-organization admin tool tries to choose another organization | No | ## Request pattern [#request-pattern] ```bash curl 'https://enterprise.spacemedia.uk/api/v1/releases' \ --header 'Authorization: Bearer 0000000000000000000000000000000000000000963fbb8e' \ --header 'Accept: application/json' \ --header 'X-User-Id: 9d7046b2-3ab1-4c9d-9bd8-90bbd22b7df2' ``` ## Supported endpoint matrix [#supported-endpoint-matrix] Only endpoints listed here accept the header. Anything else ignores it. | Endpoint | Header | Notes | | ----------------------------------------------------------------------- | ------------ | --------------------------------------------------------------------------------------------------- | | `POST /api/v1/artists` | Required | Creates the artist for the acted-for catalog workflow. | | `POST /api/v1/artists/{artist_id}` | Required | Updates an artist visible to the acted-for user. | | `POST /api/v1/releases` | Required | Creates the draft release for the acted-for user. | | `POST /api/v1/releases/{release_id}` | Required | Updates release metadata visible to the acted-for user. | | `POST /api/v1/tracks` | Required | Creates a track for the acted-for user when the release is visible. | | `POST /api/v1/tracks/{track_id}` | Required | Updates a visible track. | | `POST /api/v1/tracks/upload` | Required | Attributes the temporary audio file to the same user who will create the track. | | `POST /api/v1/tracks/upload/chunk` | Required | Uses the acted-for user as the owner of the resumable upload session. | | `GET /api/v1/tracks/upload/{upload_session_id}` | Required | Recovers only an upload owned by the same acted-for user, so the header is needed on this read too. | | `POST /api/v1/splits` | Required | Creates a split in the acted-for workflow. | | `GET /api/v1/artists` | Optional | Narrows the list to the acted-for user's catalog context. | | `GET /api/v1/releases` | Optional | Narrows the list to the acted-for user's catalog context. | | `GET /api/v1/releases/{release_id}` | Optional | Reads a release visible to the acted-for user. | | `GET /api/v1/tracks` | Optional | Narrows the list to the acted-for user's catalog context. | | `GET /api/v1/splits` | Optional | Narrows the list to splits visible to the acted-for user. | | Billing, add-ons, checkouts, theme, account, and review queue endpoints | Not accepted | These use the authenticated organization and credential owner context. | Use the same `X-User-Id` for the upload and the track create that follows it. An upload attributed to one user cannot be claimed by a track created for another. ## Ownership carryover [#ownership-carryover] When an acted-for request creates a release or track, store the returned `release_id` or `track_id`. Later workflow steps should use those public references. Do not keep sending `X-User-Id` to later substeps unless that endpoint explicitly documents support for the header. For example, release license, distribution, readiness, and submit calls use the release reference and normal organization access checks. ## Rules [#rules] * The user must belong to the same organization as the API client. * Use the public `user_id` returned by the API, never a numeric account reference. * The API client must have the operation's domain capability and `users:act-as`. * The endpoint must explicitly support acted-for user context. * Do not use this header to choose an organization. Organization context comes from authentication. ## Next [#next] With authentication settled, move on to the shared request and response rules that apply to every endpoint. # Quickstart (/delivery-api/api-quickstart) Ten minutes from credentials to your first authenticated response. **You need:** the Enterprise Delivery API add-on active, and an API key and secret created by an admin at **Settings > DDEX Gateway**. See the [Enterprise Delivery API guide](/addons/enterprise-delivery-api) if you do not have them yet. ## Choose your environment [#choose-your-environment] | Environment | Base URL | Use it for | | ----------- | ---------------------------------- | --------------------------------------------------------------------------------------------------------- | | Staging | `https://staging.spacemedia.uk` | Everything you are building. Free add-ons, isolated media, simulated delivery that never reaches a store. | | Production | `https://enterprise.spacemedia.uk` | Live automation, after sign-off. | Build against staging. Use separate credentials per environment and never reuse production credentials in test scripts, screenshots, tickets, or shared playground sessions. ### Exchange credentials for a token [#exchange-credentials-for-a-token] The credentials below are production-format placeholders. They are intentionally invalid, so replace them with your own. ```bash curl --request POST 'https://enterprise.spacemedia.uk/api/v1/token' \ --header 'X-Api-Key: 00000000-0000-4000-8000-000000000000' \ --header 'X-Api-Secret: 0000000000000000000000000000000000000000' ``` Keep the returned bearer token and its `expires_at`. Discard the key and secret from memory: they are never sent to any other endpoint. ### Make a safe read [#make-a-safe-read] `GET /api/v1/countries` is the ideal first call. It changes nothing and needs only the default `catalog:read` capability. ```bash curl 'https://enterprise.spacemedia.uk/api/v1/countries' \ --header 'Authorization: Bearer 0000000000000000000000000000000000000000963fbb8e' \ --header 'Accept: application/json' ``` You are looking for HTTP `200`, `success: true`, and reference values in `data`. ### Confirm what your credential can do [#confirm-what-your-credential-can-do] `GET /api/v1/me` returns the authenticated context. Check the capabilities before you write any code that assumes write access, because new credentials start at `catalog:read` only. ### Run a catalog smoke test on staging [#run-a-catalog-smoke-test-on-staging] Use fictional records until the integration has passed the [Go-Live Checklist](/delivery-api/go-live-checklist). 1. Create or reuse an artist. 2. Create a draft release. 3. Upload audio and keep the returned `audio_file_id`. 4. Create a track with that `audio_file_id`. 5. Save rights and distribution selections. 6. Run readiness checks. 7. Submit, then poll the simulated review and delivery lifecycle. Full detail is in [Release Lifecycle](/delivery-api/release-lifecycle). ## If the first call fails [#if-the-first-call-fails] | Response | What it means | | ------------------------- | ----------------------------------------------------------------------------------------------------- | | `401` on token exchange | The key or secret is wrong, or belongs to the other environment | | `401` on a normal request | The token expired. Refresh it before `expires_at` | | `403` | The credential lacks the capability, or a gating add-on is inactive. Do not retry | | `404` | The reference does not exist in your organization | | `429` | Slow down and respect `Retry-After`. See [Rate Limits and Retries](/delivery-api/rate-limits-retries) | More in [Errors and Status Codes](/delivery-api/errors) and [Troubleshooting](/delivery-api/troubleshooting). ## Before you touch live records [#before-you-touch-live-records] Do not point a customer integration at production until you have tested authentication, permissions, retries after timeouts, uploads, checkout behavior, readiness checks, and your support escalation path against safe sample data. ## Next [#next] # Authentication (/delivery-api/authentication) Authentication is a two-stage flow. A long-lived **key and secret** identify the integration; a short-lived **bearer token** authorizes each request. The key and secret are sent exactly once, to the token endpoint, and never again. An admin creates the key and secret at **Settings > DDEX Gateway**. For a DDEX integration, select **Create credentials** and confirm `ddex:read`, `ddex:write`, and `ddex:manage`. That screen presets those capabilities, but creating and rotating credentials is always an explicit administrator action. Copy the key and secret when they appear, because the secret is shown only once. ## Token exchange [#token-exchange] The values below are production-format placeholder credentials. They are intentionally invalid and must be replaced with credentials generated in the dashboard. ```bash curl --request POST 'https://enterprise.spacemedia.uk/api/v1/token' \ --header 'X-Api-Key: 00000000-0000-4000-8000-000000000000' \ --header 'X-Api-Secret: 0000000000000000000000000000000000000000' ``` Successful response: ```json { "success": true, "data": { "access_token": "0000000000000000000000000000000000000000963fbb8e", "token_type": "Bearer", "expires_at": "2026-07-04T11:30:00+00:00" } } ``` Access tokens always expire. The default lifetime is 1 hour, and organization administrators can configure a lifetime from 5 minutes to 24 hours. Refresh the token before `expires_at`. ## Authenticated requests [#authenticated-requests] ```bash curl 'https://enterprise.spacemedia.uk/api/v1/countries' \ --header 'Accept: application/json' \ --header 'Authorization: Bearer 0000000000000000000000000000000000000000963fbb8e' ``` ## Acting for an organization user [#acting-for-an-organization-user] Catalog write and upload endpoints require `X-User-Id` to attribute an artist, release, track, split, or upload to a user in the same organization. This does not inherit that user's dashboard roles or permissions. Authorization comes from the API client's domain capabilities, and the user reference supplies catalog ownership and quota context only. ```bash curl 'https://enterprise.spacemedia.uk/api/v1/releases' \ --header 'Authorization: Bearer 0000000000000000000000000000000000000000963fbb8e' \ --header 'X-User-Id: 9d7046b2-3ab1-4c9d-9bd8-90bbd22b7df2' ``` Use the public `user_id` returned by the API, never a numeric account reference. See [Acting for Users](/delivery-api/acting-for-users) for the full boundary. ## WordPress OAuth is a separate token [#wordpress-oauth-is-a-separate-token] The WordPress OAuth endpoints under `/api/v1/integrations/wordpress/oauth/*` do not use organization API keys or Delivery API bearer tokens. They exist so a WordPress plugin can read an authorized catalog on a site owner's behalf, and they run their own flow: 1. **Register.** SpaceMedia verifies a one-time challenge on the site's own public HTTPS host and returns a public `client_id`. There is no client secret at any point. 2. **Authorize.** The site owner approves access on a SpaceMedia consent screen in a browser session, bound with OAuth `state` and PKCE `S256`. 3. **Exchange.** The plugin trades the authorization code for a short-lived WordPress OAuth access token. 4. **Read.** `GET .../oauth/catalog` returns bounded release pages, read-only, using that token. 5. **Revoke.** `POST .../oauth/revoke` invalidates the connection and its tokens. Treat that access token as a different credential type with a different lifetime. It is not interchangeable with an organization bearer token in either direction, and the catalog endpoint accepts nothing else. Each API client receives explicit capabilities. New credentials default to `catalog:read` only. Grant the smallest set required by the integration. The `catalog:read` default applies to clients created outside the DDEX credential flow. Installing the Enterprise Delivery API add-on does not silently add delivery permissions to an existing API client. | Domain | Read capability | Write capability | | ---------------------------------------------------------- | ---------------- | ----------------------------------------------------------- | | Catalog, artists, releases, tracks, splits, and smartlinks | `catalog:read` | `catalog:write` | | Account settings and labels | `account:read` | `account:write` | | Billing, subscriptions, and checkouts | `billing:read` | `billing:write` | | Users | `users:read` | `users:manage` | | Members and roles | `members:read` | `members:manage` | | Branding and email themes | `branding:read` | `branding:manage` | | Copyright | `copyright:read` | `copyright:write` | | Release review | `review:read` | `review:process` | | Add-ons | `addons:read` | `addons:manage` | | DDEX | `ddex:read` | `ddex:write` or `ddex:manage` for connection administration | | Enterprise webhooks | `webhooks:read` | `webhooks:manage` | `users:act-as` is additionally required whenever `X-User-Id` is sent. Feedback submission uses `feedback:write`. ## Security rules [#security-rules] * Never send API key or secret after the token exchange request. * Never place bearer tokens in query strings. * Rotate credentials if a secret is exposed. * Do not use cross-organization selectors in public integrations. * Use separate API credentials per integration so access can be rotated without affecting every workflow. * Refresh the access token before `expires_at`. ## Common questions [#common-questions] **How long does a token last?** One hour by default. An admin can configure anywhere from 5 minutes to 24 hours. Refresh before `expires_at` rather than waiting for a `401`. **What happens when credentials are rotated?** Every bearer token issued from the old pair stops working immediately. Plan rotation into a maintenance window. **Can I add capabilities to an existing credential by installing an add-on?** No. Installing the Enterprise Delivery API add-on never silently widens an existing client. Capabilities are granted explicitly. **Do I need a separate credential per environment?** Yes. Staging and production credentials are not interchangeable, and reusing production credentials in test tooling is the most common way secrets leak. # Checkouts (/delivery-api/checkouts) Checkout endpoints create a payment attempt and return a `checkout_id`. Verification endpoints accept that same `checkout_id` after the payment provider completes the checkout. ## Checkout fields [#checkout-fields] | Field | Meaning | | ------------------------- | ------------------------------------------------------------------------------------------------------------------ | | `checkout_id` | Public checkout reference returned by the API. | | `redirect_url` | Hosted checkout URL when the gateway uses redirects. | | `embedded_checkout_token` | Short-lived embedded checkout token. Treat it as sensitive and only pass it to the payment collection component. | | `success_url` | URL the user returns to after successful checkout. Optional, and accepted on subscription and plan checkouts only. | | `cancel_url` | URL the user returns to after canceling checkout. Optional, and accepted on subscription and plan checkouts only. | Add-on checkouts and copyright wallet top-ups do not take return URLs. Add-on checkout takes an optional `return_to` path instead; copyright top-ups take neither. Both are resolved with the returned checkout reference and its status endpoint. ## Verification pattern [#verification-pattern] ```bash curl --request POST 'https://enterprise.spacemedia.uk/api/v1/order/checkout/verify' \ --header 'Authorization: Bearer 0000000000000000000000000000000000000000963fbb8e' \ --header 'Content-Type: application/json' \ --data '{"checkout_id":"39b189c1-8f8e-4df2-8632-176f87f791a1"}' ``` ## Checkout matrix [#checkout-matrix] | Flow | Create endpoint | Verify or status endpoint | Store | Recovery | | --------------------------- | ----------------------------------------------------------------------------------------------- | ------------------------------------------------------------------ | --------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | | Release checkout, Stripe | `POST /api/v1/order/{release_id}/checkout/stripe` | `POST /api/v1/order/checkout/verify` | `checkout_id`, `release_id` | Verify after provider return. If timeout happens, check checkout state before creating another checkout. | | Release checkout, PayPal | `POST /api/v1/order/{release_id}/checkout/paypal` | `POST /api/v1/order/checkout/verify` | `checkout_id`, `release_id` | Verify after provider return and keep the original release reference. | | Release checkout, Airwallex | `POST /api/v1/order/{release_id}/checkout/airwallex` | `POST /api/v1/order/checkout/verify` | `checkout_id`, `release_id` | If embedded checkout data expires, create a new checkout only after the first attempt is known to be unusable. | | Credits checkout | `POST /api/v1/order/credits/checkout` | `POST /api/v1/order/credits/checkout/verify` | `checkout_id` | Verify before increasing local credit balances or unlocking credit-backed actions. | | Subscription checkout | `POST /api/v1/subscriptions/subscribe/{package_id}/checkout/stripe`, `/paypal`, or `/airwallex` | `POST /api/v1/subscriptions/subscribe/{package_id}/payment-verify` | `checkout_id`, `package_id` | Verify before marking a package active in a customer system. | | Add-on checkout | `POST /api/v1/addons/{addon_slug}/checkout` | `GET /api/v1/addons/checkout/{checkout_id}/status` | `checkout_id`, add-on slug | Read add-on status after checkout before calling install or activate again. | | Copyright wallet top-up | `POST /api/v1/copyright/wallet/top-up` | `GET /api/v1/copyright/wallet/top-up/{checkout_id}/status` | `checkout_id`, wallet reference when returned | Verify before updating customer-side wallet balance. | | Payment method setup | Payment method setup endpoints under `/api/v1/billing/payment-methods/*` | Matching setup verify endpoint when provided | `payment_method_id` after success | Do not show a payment method as usable until verification succeeds. | ## Status handling [#status-handling] | Status family | Meaning | Client action | | ------------- | ------------------------------------------------------------- | -------------------------------------------------------------------------------------- | | Pending | Checkout was created but final provider outcome is not known. | Show pending state and verify again with backoff. | | Completed | Payment or setup completed. | Read related billing, subscription, wallet, or add-on state before unlocking access. | | Failed | Provider or gateway rejected the attempt. | Show a recovery action and allow a new checkout when the previous attempt is terminal. | | Cancelled | User cancelled the checkout. | Return the user to the cart or billing action. | | Expired | Checkout can no longer be completed. | Create a new checkout only if the customer still wants to proceed. | ## Invoice downloads [#invoice-downloads] Billing history items include an `invoice_pdf_url` when a PDF is available. The URL uses the same public `checkout_id` style as checkout creation and verification: ```bash curl --request GET 'https://enterprise.spacemedia.uk/api/v1/billing/invoices/39b189c1-8f8e-4df2-8632-176f87f791a1/pdf' \ --header 'Authorization: Bearer 0000000000000000000000000000000000000000963fbb8e' \ --output night-shift-records-invoice.pdf ``` ## Safe client behavior [#safe-client-behavior] * Store `checkout_id` with the local cart, release, subscription, or wallet top-up workflow. * Verify once the user returns from the provider or the embedded payment component reports completion. * Show a retry option for recoverable gateway errors. * Do not automatically create another checkout after a timeout. Read the current state first. * Do not expose API keys, webhook secrets, or live provider references in client-side logs. ## Common questions [#common-questions] **Can I trust the redirect the customer comes back on?** No. Query parameters on a return URL are navigation data. Always verify server side before granting anything. **My checkout timed out. Should I create another?** Check whether a `checkout_id` was returned and whether the related order state changed first. A second checkout can mean a second charge. **How long should I keep polling a pending checkout?** Until it reaches a terminal state: complete, failed, cancelled, or expired. Poll after the customer returns, then back off. **What should I never log?** Short-lived payment tokens such as `embedded_checkout_token`. Keep the `checkout_id` as your durable reference instead. # DDEX Gateway (/delivery-api/ddex) The Enterprise DDEX Gateway supports two equal integration paths. REST-first clients reference a SpaceMedia release and never need to generate XML. Standards-native clients submit their existing ERN message, keep the original payload intact, and use the same validation, delivery, acknowledgement, and webhook resources. The gateway is part of the Enterprise Delivery API add-on. API clients receive no DDEX access until `ddex:read`, `ddex:write`, or `ddex:manage` is explicitly granted. ## Current availability [#current-availability] DDEX public routes are currently available in staging for onboarding and conformance. Do not send production DDEX traffic until SpaceMedia confirms that the production routes and the specific live connection are active. A production `404` during this phase means the public DDEX route is not available in that environment; it is not a signal to retry or change credentials. Staging add-on activation and API testing are free. An organization administrator can activate the Enterprise Delivery API add-on, create scoped credentials under **Settings > DDEX Gateway**, exchange them at `POST /api/v1/token`, inspect the standards matrix, create locked connection profiles, run validations, and test webhook receivers. Every customer connection requires SpaceMedia connection activation review and passing conformance evidence before sandbox transport is enabled. This protects partner endpoints and is separate from release review. Customers can prepare and validate the complete integration before transport approval. ## Staging simulation and real approval boundaries [#staging-simulation-and-real-approval-boundaries] Staging provides an isolated DDEX simulator while the official licensed schema assets and external approvals are pending. It lets clients exercise the complete API lifecycle without contacting a DSP, SFTP server, or partner Web Service endpoint. | Area | Staging behavior | What it does not prove | | ---------------------- | ----------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------- | | Schema and AVS | Secure parsing plus structural, semantic, profile, AVS, DPID, identifier, catalog, contract, and state validation | Official XSD conformance against a licensed DDEX schema package | | Implementation Licence | The readiness and evidence workflow can be rehearsed | Legal approval or a DDEX Implementation Licence | | Retention | The configured 24-month policy and evidence workflow can be rehearsed | Legal approval of the retention policy | | Partner conformance | SpaceMedia can run a deterministic sandbox suite and record `SIM-STAGING-*` evidence | Bilateral evidence for a concrete live connection | | Transport | Sandbox delivery reaches simulated `acknowledged` state and returns `delivery_simulated: true` | External delivery, partner acceptance, or storefront availability | When licensed schema assets are absent, the validation report contains the informational finding `DDEX_SCHEMA_VALIDATION_SIMULATED`. The gateway never reports this as XSD validation. Connection health checks return `simulated: true` and `external_probe_performed: false` when the staging simulator handled the check. Simulated conformance can approve a sandbox connection for local testing after SpaceMedia review. It can never approve or activate a live connection. Live activation remains blocked until the official schema package, recorded licence and retention approvals, and bilateral partner conformance evidence are present. ## Choose an integration path [#choose-an-integration-path] | Path | Use it when | Source field | | ---------------- | ----------------------------------------------------------------------- | ------------------- | | REST-first | Your system manages catalog records through the Enterprise API. | `release_reference` | | Standards-native | Your system already creates ERN and needs validation, relay, or import. | `native_xml` | Send exactly one source field. Native XML is preserved without rewriting sender, recipient, identifiers, deals, or valid partner extensions. ## SpaceMedia review boundary [#spacemedia-review-boundary] The connection's `commercial_route` determines the review rule. | Commercial route | SpaceMedia review | Credits and existing delivery provider | | -------------------------- | --------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ | | `spacemedia_delivery_deal` | Transmission waits for the existing SpaceMedia review to be approved. | The normal contracted delivery workflow remains authoritative. | | `direct_partner` | No SpaceMedia review is created, awaited, or changed. | DDEX processing does not consume release credits or invoke the existing delivery provider. | Both routes still receive secure parsing, DDEX, catalog, contract, transport, and state validation. A direct partner route is not a way to bypass security or partner contract rules. ## Version policy [#version-policy] Call `GET /api/v1/ddex/standards` during onboarding and store the returned matrix. | Use | Versions | | ----------------------------------- | -------------------------------------------- | | Default generated output | ERN 4.3.2 | | REST-first generated output | ERN 4.3.2 only | | Continuous inbound and native relay | ERN 4.3.0, 4.3.1, or 4.3.2 | | Catalog migration only | ERN 3.8.2 or 3.8.3 after onboarding approval | New integrations must not request ERN 3 live feeds. The gateway does not silently downgrade messages or treat ERN 4.2 as compatible with ERN 4.3. Supported first-release profiles are Audio and Simple Audio Single. Connections pin an exact ERN version, profile, AVS revision, and either Web Service 1.8 or Cloud Storage 1.8.1 choreography. Generated operations default to AVS 011. ERN 4.3.2 uses the exact `http://ddex.net/xml/ern/432` namespace. Generated messages set `ReleaseProfileVersionId` to `Audio` or `SimpleAudioSingle`, use AVS 011, and do not add a non-standard `MessageSchemaVersionId` attribute. The gateway never treats the ERN 4.3.1 namespace as a 4.3.2 alias. DPIDs are shown in their human-readable hyphenated form in settings. DDEX XML uses the canonical form without hyphens. For example, SpaceMedia's displayed `PA-DPIDA-2025040501-N` identifier is emitted as `PADPIDA2025040501N` inside DDEX messages. ## Create a connection [#create-a-connection] Before connection creation: 1. Register and attest a sender DPID. 2. Select an integration owner from the same organization. 3. Agree the partner DPID, actions, asset rules, acknowledgements, and environment. 4. Create a sandbox connection. 5. Submit it through `POST /api/v1/ddex/connections/{reference}/activation-request`. 6. Complete SpaceMedia sandbox conformance testing before requesting live enablement. Create the sandbox connection with a new idempotency key: ```json { "name": "Partner sandbox", "partner_name": "Partner DSP", "sender_identity_reference": "1a12f4f0-07a1-4294-a556-21b0f59e8c42", "integration_owner_reference": "10f94dbe-2677-49d1-91e3-3464b40edb23", "commercial_route": "direct_partner", "direction": "outbound", "environment": "sandbox", "remote_dpid": "PA-DPIDA-2026072902-N", "ern_version": "4.3.2", "release_profile": "Audio", "avs_version": "011", "choreography": "web_service_1_8", "hosting_mode": "spacemedia_managed", "auth_type": "bearer", "agreement_reference": "PARTNER-SANDBOX-2026", "capabilities": ["insert", "update", "global_takedown"] } ``` For `spacemedia_delivery_deal`, omit `sender_identity_reference`; SpaceMedia supplies the platform sender identity. For `direct_partner`, the sender identity is required and must belong to the same organization. Create an explicit deal profile before a REST-first delivery that needs commercial rights: ```json { "name": "Worldwide streaming", "commercial_model": "SubscriptionModel", "use_types": ["OnDemandStream"], "territories": ["GB", "US", "DE"], "valid_from": "2026-08-21T00:00:00Z", "valid_until": null, "terms": { "rights_claimed": true } } ``` Creating a connection never enables transport. It starts as a locked draft. An activation request submits it for SpaceMedia connection review and sandbox conformance testing. Transport becomes available only after the applicable connection and production-readiness checks pass. This operational review applies to all connections and is separate from SpaceMedia release review. A partner certificate is not required. For live activation, submit a live connection for the same organization, partner DPID, ERN, release profile, AVS, and choreography as a passing sandbox connection. Live connections remain disabled until licensing, retention, bilateral agreement, connection health, compatible transport, and production-access requirements are confirmed. Staging cannot contact live DDEX endpoints. Sender-hosted Web Service feeds are available for outbound conformance. Partner-managed outbound SFTP for Cloud Storage 1.8.1 is available with pinned host keys and streamed, size-checked, atomic publication. Web Service recipient polling and SpaceMedia-managed SFTP are enabled per connection when available and after bilateral conformance. Their unavailability does not prevent a separate connection from using another supported transport. A connection health check reports the applicable requirements explicitly. Rotate connection credentials through `POST /api/v1/ddex/connections/{reference}/rotate-secret`, then run `POST /api/v1/ddex/connections/{reference}/health-check`. Stored credentials are encrypted and never returned. Connection capability and contract profiles are immutable versions. To replace one, create a complete connection profile with `supersedes_reference` set to the prior connection reference. The prior profile becomes superseded, in-flight evidence keeps its original profile, and the replacement starts in testing. ## Validate without transmission [#validate-without-transmission] ```bash curl --request POST \ --url https://staging.spacemedia.uk/api/v1/ddex/validations \ --header "Authorization: Bearer $SPACEMEDIA_TOKEN" \ --header "Content-Type: application/json" \ --header "Idempotency-Key: validation-20260729-001" \ --data '{ "connection_reference": "3bc1f628-60af-4db2-b984-321c1525df20", "release_reference": "b7a15d95-58f6-4f67-b5d1-89f4f5bfb4d8", "deal_profile_reference": "bb9b8f3b-55b1-498f-a484-05155b8950ef", "action": "insert" }' ``` The API returns `202` with a canonical `status_url`, correlation key, current state, and findings. Validation itself can finish in the first request, but clients must still handle the operation as asynchronous. On staging, inspect findings for `DDEX_SCHEMA_VALIDATION_SIMULATED` before treating a successful result as official XSD conformance. Every finding includes a stable code, family, severity, stage, retryability, JSON Pointer or XPath, explanation, remediation, optional partner rule, and correlation key. A successful asynchronous operation returns a public operation reference, current state, findings, canonical status URL, and correlation key: ```json { "data": { "reference": "45be9e79-f39e-4cf9-bfc8-bf9f10481da6", "status": "ready", "review_status": "not_required", "transport_status": "not_started", "partner_status": "not_started", "findings": [] }, "status_url": "/api/v1/ddex/messages/45be9e79-f39e-4cf9-bfc8-bf9f10481da6", "correlation_key": "ddex_01J2M4Y8Q7K3" } ``` Validation includes secure XML parsing, exact namespace/schema/profile/AVS pins, DPIDs, GTIN check digits, ISRC format, P-line and C-line ownership, dates, territories, verified-master MIME/size/hash, deal validity, partner-required fields, allowed actions, transport credentials, choreography/auth compatibility, duplicate messages, update ordering, and acknowledged identifier locks. Download the complete report from `GET /api/v1/ddex/messages/{reference}/validation-report`. Common stable finding codes: | Family | Codes | | -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | | Secure input | `DDEX_XML_EXTERNAL_ENTITY`, `DDEX_XML_SIZE_LIMIT`, `DDEX_XML_DEPTH_LIMIT`, `DDEX_XML_MALFORMED` | | Standard | `DDEX_STANDARD_UNSUPPORTED`, `DDEX_NAMESPACE_VERSION_MISMATCH`, `DDEX_RELEASE_PROFILE_MISMATCH`, `DDEX_AVS_VERSION_MISMATCH`, `DDEX_XSD_INVALID` | | Identity and catalog | `DDEX_DPID_MISMATCH`, `DDEX_XML_DPID_MISMATCH`, `DDEX_GTIN_INVALID`, `DDEX_ISRC_INVALID`, `DDEX_COPYRIGHT_FIELD_REQUIRED`, `DDEX_MASTER_TECHNICAL_INVALID` | | Deal and contract | `DDEX_DEAL_PROFILE_REQUIRED`, `DDEX_DEAL_PROFILE_INACTIVE`, `DDEX_DEAL_TERRITORY_MISMATCH`, `DDEX_ACTION_NOT_CONTRACTED`, `DDEX_PARTNER_FIELD_REQUIRED` | | Review and transport | `DDEX_SPACEMEDIA_RELEASE_REQUIRED`, `DDEX_SPACEMEDIA_REVIEW_REQUIRED`, `DDEX_TRANSPORT_CONFIGURATION_INCOMPLETE`, `DDEX_TRANSPORT_AUTH_INCOMPATIBLE` | | State and import | `DDEX_DUPLICATE_MESSAGE`, `DDEX_UPDATE_BEFORE_INSERT`, `DDEX_ACKNOWLEDGED_IDENTIFIER_CHANGED`, `DDEX_IMPORT_CATALOG_COLLISION` | ## Deliver a release [#deliver-a-release] TypeScript: ```ts const result = await fetch("https://staging.spacemedia.uk/api/v1/ddex/deliveries", { method: "POST", headers: { Authorization: `Bearer ${process.env.SPACEMEDIA_TOKEN}`, "Content-Type": "application/json", "Idempotency-Key": "delivery-20260729-001" }, body: JSON.stringify({ connection_reference: "3bc1f628-60af-4db2-b984-321c1525df20", release_reference: "b7a15d95-58f6-4f67-b5d1-89f4f5bfb4d8", deal_profile_reference: "bb9b8f3b-55b1-498f-a484-05155b8950ef", action: "insert" }) }); if (result.status !== 202) throw new Error(`DDEX delivery failed: ${result.status}`); const operation = await result.json(); ``` PHP: ```php $response = $client->request('POST', '/api/v1/ddex/deliveries', [ 'headers' => [ 'Authorization' => 'Bearer '.$token, 'Idempotency-Key' => 'delivery-20260729-001', ], 'json' => [ 'connection_reference' => '3bc1f628-60af-4db2-b984-321c1525df20', 'release_reference' => 'b7a15d95-58f6-4f67-b5d1-89f4f5bfb4d8', 'deal_profile_reference' => 'bb9b8f3b-55b1-498f-a484-05155b8950ef', 'action' => 'insert', ], ]); ``` Clients choose `insert`, `update`, `territorial_takedown`, `global_takedown`, or `purge`. Do not classify a change as metadata-only or resource-only. Updates are complete statements of current and future deal truth. Unchanged binaries may be omitted when the connection permits it. REST-first `insert`, `update`, and `territorial_takedown` operations require `deal_profile_reference`. The gateway does not guess commercial rights. A generated `global_takedown` intentionally omits the deal list, while `purge` creates a `PurgeReleaseMessage` for corrupt catalog state. On staging, an approved sandbox connection uses the isolated transport simulator. Poll the message until it reaches `acknowledged`, then inspect `delivery_simulated`. A value of `true` confirms only that the local contract, queue, packaging, status, acknowledgement, and webhook lifecycle completed without external delivery. A territorial takedown also requires an explicit subset of the selected deal profile and an ISO 8601 effective time with timezone: ```json { "connection_reference": "3bc1f628-60af-4db2-b984-321c1525df20", "release_reference": "b7a15d95-58f6-4f67-b5d1-89f4f5bfb4d8", "deal_profile_reference": "bb9b8f3b-55b1-498f-a484-05155b8950ef", "action": "territorial_takedown", "metadata_overlay": { "takedown": { "territories": ["DE"], "effective_at": "2026-08-01T00:00:00+02:00" } } } ``` ## Native relay and import [#native-relay-and-import] Use `native_xml` instead of `release_reference`: ```json { "connection_reference": "3bc1f628-60af-4db2-b984-321c1525df20", "action": "insert", "native_xml": "..." } ``` `POST /api/v1/ddex/uploads` preserves and validates a native message. `POST /api/v1/ddex/imports` stages a create-only inbound import under the connection's same-organization integration owner. Imports are atomic and create drafts only. UPC, ISRC, source-message, or catalog collisions block the complete import rather than creating partial catalog records. Fields that cannot safely round-trip through the normalized catalog remain attached to the original message and appear in `unmapped_fields`. Follow the returned import `status_url`, or call `GET /api/v1/ddex/imports/{reference}`, to inspect the canonical import result. ## State model [#state-model] Normal control progression: `accepted → validating → ready → queued → packaging → available or transferring → transferred → claimed → acknowledged` Exceptional states are `blocked`, `rejected`, `failed`, `cancelled`, and `expired`. Review, transport, partner, and webhook states are separate. Recipient `DELETE` confirms claim only. It is not proof of processing or storefront availability. The API exposes `live` only after an explicit partner processing status reports it. ## Retry and cancellation [#retry-and-cancellation] * Reusing an idempotency key with the same request safely replays the outcome. * Reusing it with a different request returns a conflict. * Validation errors and partner rejections are not retried automatically. * Temporary timeouts, resets, throttling, and server failures use bounded retry with backoff. * Retry only messages that the API reports as recoverable. * Cancel only work that has not been claimed. ## Web Service and Cloud Storage [#web-service-and-cloud-storage] Web Service 1.8 uses the sender-hosted feed and recipient claim semantics. Resource downloads use `GET /api/v1/ddex/messages/{reference}/resources/{resourceReference}` with stable authenticated URLs, SHA-256 checksums, `ETag`, and byte-range requests through the standard `Range` header. Processing status remains separate from claim. Read the Atom feed through `GET /api/v1/ddex/connections/{reference}/feed`. A feed contains at most the current available message for a release. A superseded payload URL returns `404`. Cloud Storage 1.8.1 supports release-by-release and negotiated batches. A message cannot enter multiple open batches. Batch completion and its manifest checksum are published after all message artifacts. ## Conformance checklist [#conformance-checklist] * Sandbox DPIDs and credentials are exchanged out of band. * Exact ERN, profile, AVS, and choreography match the connection. * Single, album, update, takedown, purge, invalid message, retry, claim, and acknowledgement fixtures pass. * Release-by-release and batch flows are tested separately. * Direct partner tests confirm no SpaceMedia review or credit mutation. * SpaceMedia delivery deal tests confirm transmission cannot start before review approval. * Duplicate, stale, out-of-order, and identifier-changing updates are rejected. * Webhook signatures, duplicates, retries, ordering, and secret rotation are verified. * Operational owners agree acknowledgement deadlines and escalation contacts. ## Related pages [#related-pages] # Delivery Statuses (/delivery-api/delivery-statuses) Release delivery is not one synchronous API call. A release moves through draft preparation, readiness checks, review, downstream delivery, and destination-specific outcomes. ## Status fields [#status-fields] | Field | Meaning | | -------------------- | ------------------------------------------------------------------------------- | | `status` | General release state shown on release records and queues. | | `review_id` | Public review reference when the release is in a review workflow. | | `review_status` | Organization-visible review state. | | `delivery_status` | Organization-visible delivery state after review or delivery processing begins. | | `delivery_simulated` | `true` when staging completed the lifecycle locally without external delivery. | | `submitted_at` | Timestamp for when submission was recorded, when available. | ## Integration sequence [#integration-sequence] 1. Keep the release as a draft while metadata, artwork, audio, rights, and destinations are incomplete. 2. Run `GET /api/v1/releases/{release_id}/pre-qc` before submission. 3. Submit with `POST /api/v1/releases/{release_id}/submit` only when no blocking issue remains. 4. Monitor submitted releases through release review endpoints available to the authenticated organization. 5. Monitor sent or delivered release queues for delivery outcomes. ## Draft and readiness states [#draft-and-readiness-states] | State | Meaning | Client action | | ----------------------------- | ------------------------------------------------------------ | --------------------------------------------------------------- | | Draft | Release is editable and not submitted. | Continue adding metadata, tracks, rights, and distribution. | | Readiness has blocking issues | Pre-submission checks found missing or invalid data. | Fix the fields listed by the readiness response. Do not submit. | | Readiness has warnings | The release may be close to valid but needs operator review. | Decide whether to fix warnings before submission. | | Ready to submit | No blocking issue remains. | Submit once the operator confirms metadata and destinations. | ## Review states [#review-states] Actual values are returned by the API and can evolve, but integrations should handle these state families: | State family | Meaning | Client action | | --------------------------------- | ----------------------------------------- | -------------------------------------------------------------------- | | `submitted` or `pending_review` | Release is waiting for review. | Poll at a moderate interval. Do not resubmit in a tight loop. | | `in_review` | Review is active. | Avoid metadata changes unless the endpoint allows them. | | `changes_requested` or `rejected` | Review found blocking issues. | Read the reason, fix metadata or assets, then resubmit when allowed. | | `approved` | Review accepted the release for delivery. | Monitor delivery status. | | `sent` | Release was sent onward for delivery. | Monitor destination outcome. | Clients must be tolerant of additional status values and display unknown values without crashing. ## Delivery states [#delivery-states] | State family | Meaning | Client action | | ------------------------ | -------------------------------------------------------------- | ----------------------------------------------------------------------------- | | `pending_review` | Delivery has not started because review is still pending. | Wait for review outcome. | | `queued` or `processing` | Delivery is being prepared or sent. | Poll with a longer interval. | | `sent` | Delivery package was sent onward. | Wait for downstream result. | | `delivered` | Release is marked delivered in the visible workflow. | Store the status and stop frequent polling. | | `failed` or `rejected` | Delivery failed or was rejected. | Read the reason and fix the root cause before resubmission. | | `partial` | Some destinations accepted or progressed while others did not. | Show destination-level detail when available and resolve failed destinations. | Do not treat `sent` as the same as live on every DSP. Storefront availability can lag behind delivery acceptance. On staging, no status represents real DSP delivery. A terminal simulated result includes `delivery_simulated: true`; use it to validate client behavior, retries, polling, and operator displays. ## Polling intervals [#polling-intervals] | Workflow | Endpoint | Fields to inspect | Suggested interval | Stop condition | | ------------------------ | -------------------------------------------- | -------------------------------------------------------------------------------- | ---------------------------------------------- | ----------------------------------------------------------------------------------------- | | Readiness | `GET /api/v1/releases/{release_id}/pre-qc` | Blocking and warning issue groups returned by the check. | Run after each metadata or asset fix. | No blocking issue remains, or the operator leaves the edit flow. | | Submitted review queue | `GET /api/v1/qc/releases/submitted` | `review_id`, `review_status`, `delivery_status`, `submitted_at`, release fields. | 30 to 60 seconds while an operator is waiting. | Release leaves submitted review, needs changes, or is no longer relevant to the operator. | | Sent review queue | `GET /api/v1/qc/releases/sent` | `review_id`, `delivery_status`, `submitted_at`, release fields. | 5 to 30 minutes. | Delivery reaches a terminal state or moves into manual handling. | | All visible review queue | `GET /api/v1/qc/releases/all` | Same queue fields plus list pagination metadata. | 5 to 15 minutes for background sync. | Local state is synchronized through the latest page. | | Checkout result | Matching checkout verify or status endpoint. | `checkout_id`, payment status fields, related billing or add-on state. | After provider return, then back off. | Checkout is complete, failed, cancelled, or expired. | ## Common blockers [#common-blockers] | Blocker | Cause | Fix | | ------------------------------- | ----------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- | | Release stays in draft | Submission was never called or readiness checks failed. | Run readiness checks and submit only after blockers are fixed. | | Submission fails | Missing metadata, missing rights, invalid cover art, no tracks, or no destinations. | Fix the validation errors and rerun readiness checks. | | Review rejects release | Metadata, rights, artwork, or audio does not meet delivery requirements. | Fix the listed issue, then resubmit if allowed. | | Delivery is partial | One or more destinations need different metadata, territory, or rights handling. | Inspect destination-level details when returned and resolve only the failed destinations. | | Status is unknown to the client | API added or returned a status the client did not map. | Display the raw value and log it for mapping update. | ## Common questions [#common-questions] **Does `sent` mean the release is live?** No. It means the delivery package went onward. Storefront availability lags behind delivery acceptance and varies per destination. **What should my client do with a status it has never seen?** Display the raw value, log the endpoint and public reference, and keep the record visible to an operator. Never let an unknown status trigger irreversible automation. **How often should I poll?** As slowly as the workflow tolerates. 30 to 60 seconds while an operator is watching a submitted release, 5 to 30 minutes for delivery outcomes, and longer for background sync. **A staging release shows `delivered`. Does that prove anything?** Only that your client handled the contract correctly. Check `delivery_simulated`. On staging it is `true` and no release ever reaches a store. ## Next [#next] # Errors and Status Codes (/delivery-api/errors) Errors come from request validation, authorization, resource lookup, gateway checks, and endpoint-specific business rules. The single most useful habit: **read the status code before the message**. `403` and `404` look similar in a log but mean opposite things, and only one of them is worth investigating on your side. ## Standard error envelope [#standard-error-envelope] ```json { "success": false, "message": "The title field is required.", "errors": { "title": ["The title field is required."] } } ``` Unexpected server failures also include a stable machine code and a support-safe reference: ```json { "success": false, "message": "The request could not be completed.", "error_code": "public_api_request_failed", "error_reference": "fa711c5c-0704-4c8f-86dc-76719fbdbb02" } ``` Provide `error_reference` to SpaceMedia support. Do not send bearer tokens, API credentials, or private provider data. ## Common status codes [#common-status-codes] | Status | Meaning | | ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `400` | Bad request, invalid token state, malformed date range, or business rule failure. | | `401` | Missing bearer token, invalid API credentials, or expired token. | | `402` | Organization or user quota, or a payment requirement, blocks the action. | | `403` | Permission rules or required account access denied the action. The endpoint exists but the current user cannot perform it. | | `404` | Resource not found in the authenticated organization. | | `409` | The requested state conflicts with current server state, such as repeating a transition or superseding an already replaced configuration. Read the current resource before deciding whether to retry. | | `422` | Request validation failed or checkout/top-up input is incomplete. | | `429` | The request exceeded a rate limit. Respect `Retry-After` when it is present and retry with backoff. | | `500` | Gateway, storage, or unexpected server error. | ## Validation examples [#validation-examples] Release create/update requires a square cover image between 3000x3000 and 5000x5000 pixels, at least one Primary Artist, valid title/version metadata, and a valid release format. Track create/update normalizes ISRC and ISWC values before validation and requires at least one Primary Artist plus at least one Composer credit. Revenue split create/update requires `title`, `percentage`, and one beneficiary reference: `beneficiary_id`, `beneficiary_email`, or `email`. Release and track assignments are optional unless the endpoint-specific request body says otherwise. ## Retry guidance [#retry-guidance] | Failure | Recommended action | | --------------------------- | ---------------------------------------------------------------------------------------------------- | | `401` token expired | Create a new bearer token and retry once. | | `403` permission denied | Check the acting user, member role, and organization add-on access. Do not retry automatically. | | `404` not found | Confirm the reference belongs to the authenticated organization. | | `409` state conflict | Read the current resource and continue from its canonical state. Do not blindly repeat the write. | | `422` validation failed | Fix the field listed in `errors` before retrying. | | `429` rate limited | Wait for `Retry-After`, then retry with exponential backoff and jitter. | | `500` server failure | Record `error_code` and `error_reference`, then retry only when the operation is documented as safe. | | Payment gateway unavailable | Show a user-facing payment error and retry only after checking gateway status. | | Upload interrupted | Retry the failed upload or chunk with the same local file metadata. | For operation-level retry safety, see [Rate Limits and Retries](/delivery-api/rate-limits-retries). Create, checkout, submit, top-up, install, and publish actions should read current state before repeating after a timeout. ## Common questions [#common-questions] **Is `403` ever worth retrying?** No. It means a capability, permission, or add-on check failed. Retrying produces the same result. Check the credential's capabilities and whether a gating add-on is active. **Why do I get `404` for a reference I can see in the dashboard?** The reference belongs to a different organization than the credential, or it is an internal identifier rather than the public one. **What is `402` telling me?** A quota or payment requirement is blocking the action, not a technical fault. **What should I send to support?** The `error_code` and `error_reference` from the response, plus the endpoint, method, timestamp, and public reference. Never send bearer tokens, API secrets, or provider credentials. **Where is the page metadata documented?** On [Pagination and Filtering](/delivery-api/pagination-filtering), together with search, sorting, and the different envelope the staging DDEX and webhook collections use. # Response Conventions (/delivery-api/example-data) SpaceMedia API responses use stable public references and local field names. The same naming style appears in examples, endpoint responses, webhooks when available, and support conversations. ## Identifier rules [#identifier-rules] | Object | Public field | | ------------------------ | ------------------- | | User | `user_id` | | Member | `member_id` | | Role | `role_id` | | Artist | `artist_id` | | Release | `release_id` | | Track | `track_id` | | Revenue split | `split_id` | | Subscription | `subscription_id` | | Checkout | `checkout_id` | | Smartlink | `smartlink_id` | | Payment method | `payment_method_id` | | Package | `package_id` | | Invitation | `invitation_id` | | Label | `label_id` | | Temporary uploaded audio | `audio_file_id` | Responses do not include duplicate `id` and `uuid` fields. Numeric internal references are not part of the public API. When an upload returns a temporary audio reference, the field is called `audio_file_id`. ## Sample data style [#sample-data-style] * Use realistic labels, distributors, artists, releases, and track metadata. * Use production-style fictional domains such as `northstar-distribution.co.uk` for examples. * Use production-format placeholder credentials that are clearly invalid, such as `00000000-0000-4000-8000-000000000000`, `0000000000000000000000000000000000000000`, and `0000000000000000000000000000000000000000963fbb8e`. * Use stable public references for objects. * Do not copy customer data, real payment secrets, cookies, or live provider references into examples. ## Common questions [#common-questions] **Why does the API not return an `id` field?** Objects carry one purpose-named public reference such as `release_id`. Internal numeric identifiers are not part of the public contract, and there are no duplicate `id` and `uuid` fields to disambiguate. **Can I shorten or re-encode a public reference?** No. Store and send it exactly as returned. **Which reference does an upload return?** `audio_file_id`, and it is temporary. The stable track reference is `track_id`, returned when the track is created. **What should example data look like in my own tests?** Realistic but clearly fictional, using placeholder credentials that cannot work. Never copy customer data, live provider references, or real payment secrets into fixtures. # Go-Live Checklist (/delivery-api/go-live-checklist) Use this checklist before a customer integration moves from test data to live operations. It is written for B2B clients connecting catalog, user, billing, branding, or reporting workflows. ## Access and ownership [#access-and-ownership] | Check | Why it matters | | --------------------------------------------------------------- | -------------------------------------------------------------------------- | | Enterprise Delivery API is active for the organization. | Protected API endpoints require the product to be enabled. | | API credentials are owned by an accountable admin. | Credentials must be rotated without breaking unrelated systems. | | Separate credentials exist for each integration. | One compromised integration should not affect every workflow. | | Required add-ons are active. | Members, Smartlinks, Theme Editor, and other modules can be product-gated. | | Acting-for-user behavior is tested only on supported endpoints. | `X-User-Id` should not be treated as universal impersonation. | ## Environment and data [#environment-and-data] | Check | Why it matters | | ----------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- | | Staging tests use `https://staging.spacemedia.uk`. | Integration rehearsals should not use live catalog or payment data. | | Production cutover uses `https://enterprise.spacemedia.uk`. | Live automation should target the documented production host only after sign-off. | | Credentials are separate per environment. | A staging client should not be able to affect production records. | | Sample data is fictional and clearly marked. | Test releases should not leak real artist, customer, or payment data. | | Staging submission and terminal simulated delivery are tested. | Staging follows the public lifecycle but cannot send a release to a DSP. | | The client recognizes `delivery_simulated`. | A staging terminal state must not be presented as real storefront availability. | | Expired staging media can be uploaded again. | Staging release files are temporary and automatically removed after retention. | | Public references are stored in your system. | Follow-up calls need `release_id`, `track_id`, `artist_id`, `user_id`, and similar public references. | | Internal numeric references are not stored or shown to operators. | Public integrations must not depend on internal storage references. | ## Authentication [#authentication] | Check | Why it matters | | ---------------------------------------------------- | ----------------------------------------------------------------------------------------- | | Token exchange works in the target organization. | API credentials alone are not sent to protected endpoints. | | Token expiry is handled before protected calls fail. | Avoid repeated `401` failures in production. | | Secrets are never logged. | API key, API secret, bearer token, payment tokens, and webhook secrets must stay private. | | Support screenshots are sanitized. | Operators often paste playground or console output during go-live. | ## Catalog workflow [#catalog-workflow] | Check | Why it matters | | ------------------------------------------------------------ | ------------------------------------------------------------------------- | | Artist create and list flows are tested. | Release creation depends on stable artist references. | | Release create uses multipart data when uploading cover art. | Cover upload and metadata must be sent in the correct format. | | Audio upload returns `audio_file_id`. | Track creation must use the upload reference returned by the API. | | Track creation returns `track_id`. | Later ordering, attachment, and reporting use the stable track reference. | | License, territories, and distribution selections are saved. | Delivery cannot be valid without rights and destination data. | | Readiness checks run before submission. | Blocking issues should be fixed before review. | | Submission is not automatically retried after timeout. | Fetch state before submitting again. | | Review and delivery polling is bounded. | Avoid customer systems over-polling during downstream delays. | ## Metadata [#metadata] | Check | Why it matters | | ----------------------------------------------------- | ------------------------------------------------------------------ | | Titles and versions are clean. | DSPs can reject titles with promo text or duplicated version data. | | Artist roles are structured. | Artist display and contributor credits depend on role fields. | | Explicit flags are accurate. | Incorrect explicit metadata can block or misrepresent delivery. | | Artwork passes size and content rules. | Cover art failures are a common release blocker. | | UPC, ISRC, and ISWC values are correct when supplied. | Identifier mistakes can cause catalog conflicts. | | Territories match the customer's rights. | Wrong territories can create rights issues or missed delivery. | ## Billing and checkouts [#billing-and-checkouts] | Check | Why it matters | | -------------------------------------------------- | ------------------------------------------------------------ | | Checkout creation stores `checkout_id`. | Verification and support need the public checkout reference. | | Embedded checkout data is treated as short-lived. | It is not a durable payment reference. | | Retry behavior avoids duplicate checkout creation. | Timeouts can otherwise create multiple payment attempts. | | Failed or expired checkouts show recovery actions. | Operators need a clear path to retry safely. | ## SDK and client behavior [#sdk-and-client-behavior] | Check | Why it matters | | ---------------------------------------------- | ----------------------------------------------------------------------- | | Generated client preserves public field names. | SDKs should not rename public references into confusing generic fields. | | Pagination helpers expose `meta`. | Integrations must know when list sync is complete. | | Error handlers parse `errors`. | Field-level validation helps operators fix payloads quickly. | | Retry policy follows the documented table. | Prevent duplicate releases, checkouts, top-ups, and submissions. | | Unknown status values are displayed safely. | New states should not break customer dashboards. | ## Production cutover [#production-cutover] 1. Run the full workflow with fictional records. 2. Verify expected records in the dashboard. 3. Confirm no internal references or secrets appear in logs. 4. Confirm retry behavior with a forced timeout in the customer client. 5. Confirm validation error display with an intentionally incomplete draft. 6. Confirm checkout failure recovery if the integration uses payments. 7. Confirm review and delivery polling does not exceed the agreed operating volume. 8. Lock credentials to the production integration owner. 9. Archive test data or keep it clearly labeled. 10. Switch the customer system to live records only after sign-off. ## Support packet [#support-packet] For launch support, prepare: * Organization name. * Integration owner contact. * Endpoint groups used. * Public references for affected records. * Timestamp and timezone. * Sanitized request and response examples. * Client version or SDK version. * Steps already retried. Do not include secrets, payment provider references, raw customer credentials, or private keys. ## Common questions [#common-questions] **How much of this can I skip if the integration is small?** The authentication, retry, and support items apply at any size. Catalog and billing sections apply only if you use those areas. **What proves staging readiness?** A complete rehearsal: token exchange, a catalog flow through submission, a simulated review and delivery result, and a deliberate failure you recovered from. See [Staging Environment](/delivery-api/staging-environment). **Do I need new credentials for production?** Yes. Staging and production credentials are separate, and reusing one across environments is the most common way secrets leak. **Who signs off?** Name an owner for the credential, the integration, and the escalation path before cutover. An integration nobody owns is the one that fails silently. # Delivery API (/delivery-api) The Delivery API connects your own systems to SpaceMedia: create artists and releases, upload audio, run readiness checks, submit for review, track delivery, and drive billing and add-on workflows without anyone opening the dashboard. Everything is scoped to the organization that owns the credentials. There is no cross-organization access and no organization selector. ## Two things before you start [#two-things-before-you-start] 1. The **Enterprise Delivery API** add-on must be active for your organization. 2. An admin creates API credentials at **Settings > DDEX Gateway**. The secret is shown once. Both are covered in the [Enterprise Delivery API guide](/addons/enterprise-delivery-api). ## Pick your path [#pick-your-path] | You are building | Read in this order | | --------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | A catalog or delivery integration | [Quickstart](/delivery-api/api-quickstart), [Release Lifecycle](/delivery-api/release-lifecycle), [Uploads](/delivery-api/uploads), [Metadata Style Guide](/delivery-api/metadata-style-guide), [Delivery Statuses](/delivery-api/delivery-statuses) | | A billing or checkout integration | [Authentication](/delivery-api/authentication), [Checkouts](/delivery-api/checkouts), [Rate Limits and Retries](/delivery-api/rate-limits-retries) | | A DDEX partner integration | [DDEX Gateway](/delivery-api/ddex), [Webhooks](/delivery-api/webhooks), [Staging Environment](/delivery-api/staging-environment) | | An SDK or client library | [Response Conventions](/delivery-api/example-data), [Pagination and Filtering](/delivery-api/pagination-filtering), [SDK Generation](/delivery-api/sdk-generation) | | Anything, before going live | [Go-Live Checklist](/delivery-api/go-live-checklist), [Troubleshooting](/delivery-api/troubleshooting) | ## The five rules that prevent most incidents [#the-five-rules-that-prevent-most-incidents] 1. **Rehearse on staging first.** [Staging](/delivery-api/staging-environment) mirrors production behavior, gives you free add-ons, and never delivers to a store. 2. **Never retry a write blindly.** After a timeout, read the current state before repeating a create, submit, checkout, or install. See [Rate Limits and Retries](/delivery-api/rate-limits-retries). 3. **Store public references, not your own identifiers.** `release_id`, `track_id`, and `checkout_id` are the contract. See [Response Conventions](/delivery-api/example-data). 4. **Tolerate unknown status values.** Statuses can be added. Display what you receive rather than crashing. See [Delivery Statuses](/delivery-api/delivery-statuses). 5. **Grant the smallest capability set.** New credentials start at `catalog:read`. Add nothing you cannot justify. See [Authentication](/delivery-api/authentication).
The contract is the source of truth

Every endpoint page is generated from the same OpenAPI specification used for validation and SDK generation. If a narrative page and the contract disagree, stop and report the mismatch rather than guessing.

## Environments [#environments] | Environment | Base URL | | ----------- | ---------------------------------- | | Production | `https://enterprise.spacemedia.uk` | | Staging | `https://staging.spacemedia.uk` | Use separate credentials per environment. Never send production secrets to staging tooling, screenshots, or support tickets. Contract release notes are published in the [Delivery API changelog](/changelog/delivery-api). # How the API Works (/delivery-api/introduction) Four ideas explain almost everything about how this API behaves. Understanding them up front saves a lot of debugging later. ## 1. Scope comes from the credential [#1-scope-comes-from-the-credential] There is no organization parameter anywhere in the API. The credential you authenticate with determines which organization you operate in, and nothing you send can change that. A `404` therefore means "not found in your organization", which is often the real answer when an identifier looks valid but belongs to someone else. ## 2. Authorization is capability-based [#2-authorization-is-capability-based] Each API client carries an explicit list of capabilities such as `catalog:read` or `billing:write`. New credentials start with `catalog:read` and nothing else. Capabilities belong to the client, not to a person. They do not inherit from a staff member's dashboard role. When an integration acts for one of your users, that supplies catalog ownership context, not extra authority. See [Authentication](/delivery-api/authentication) and [Acting for Users](/delivery-api/acting-for-users). A `403` means the endpoint exists and you are authenticated, but a capability, permission, or add-on check failed. It is never a signal to retry. ## 3. Some endpoint groups need an add-on as well [#3-some-endpoint-groups-need-an-add-on-as-well] Buying API access does not expose product areas you have not bought. | Endpoint group | Also requires | | ------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | | Members and member roles | [Team Members](/addons/members-management) add-on active | | Smartlinks create, update, sync, preferences, analytics | [Smartlink](/addons/release-smartlinks) add-on active | | Theme editor draft and publish | Theme Editor active | | Add-on checkout and install actions | The authenticated admin can manage add-ons | | DDEX and enterprise webhooks | Explicit DDEX or webhook capabilities plus current staging onboarding. Production use starts only after SpaceMedia confirms route and connection activation | ## 4. Every response uses the same envelope [#4-every-response-uses-the-same-envelope] Responses carry `success`, an optional `message`, `data`, an optional `meta` for pagination, and an optional `errors` map. Objects identify themselves with one stable public reference such as `user_id`, `release_id`, `track_id`, or `checkout_id`. Internal numeric identifiers are never part of the public API. See [Response Conventions](/delivery-api/example-data). ## Endpoint families [#endpoint-families] | Family | Scope | | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | Auth | Exchange organization API key and secret for a bearer token, then validate token expiry. | | Account | Current profile, sessions, personal information, notification preferences, and custom labels. | | Artists, releases, tracks | Catalog workflows available to permitted organization users. | | Splits | Revenue split listing, creation, updates, and confirmations. | | Users and members | Organization users, team members, invitations, roles, permissions, suspension, and related records where allowed. | | Packages and payments | Membership packages, pay-per-release plans, upgrade options, subscriptions, checkouts, credit purchases, payment methods, and checkout verification. | | Add-ons | Organization add-on checkout, install, activation, deactivation, uninstall, and status actions. | | Copyright | Organization copyright summary, statistics, wallet reads, wallet top-ups, release reads, and top-up status. | | Release review | Release review queues where the organization has dashboard access. | | Smartlinks | Branded release landing pages, DSP destinations, analytics, and preferences. | | Theme and email theme | Organization branding drafts, preview, and publish actions. | | Feedback | Organization-visible feedback submission for product, catalog, billing, and API workflows. | | Reference | Countries and release territories. | | DDEX | Versioned partner connections, validations, exports, deliveries, imports, acknowledgements, and conformance workflows for approved Enterprise Delivery API customers. | | Enterprise webhooks | Signed DDEX lifecycle events, delivery attempts, testing, replay, pause, and secret rotation. | | WordPress OAuth | Registration, PKCE consent, and read-only catalog access for a WordPress plugin. Uses its own short-lived token, not an organization bearer token. See [Authentication](/delivery-api/authentication). | ## Base URLs [#base-urls] | Environment | Base URL | | ----------- | ---------------------------------- | | Production | `https://enterprise.spacemedia.uk` | | Staging | `https://staging.spacemedia.uk` | Use separate credentials per environment. ## Common questions [#common-questions] **Is the API public in the sense of unauthenticated?** No. Public means an external organization can call it after credential, capability, and permission checks pass. **Can one credential reach two organizations?** No. If you operate several organizations, you need separate credentials for each. **Does the playground send real requests?** Yes, to whichever base URL is selected. Use sample values until you are deliberately testing with your own credentials, and never paste production secrets into a shared session. **Where do I find the exact request and response shape?** On the endpoint page for that operation. Those pages are generated from the [OpenAPI contract](/delivery-api/openapi.json), which is authoritative. ## Next [#next] Work through the [Quickstart](/delivery-api/api-quickstart), then follow the recipe that matches your integration in [Workflows](/delivery-api/workflows). # LLM Context (/delivery-api/llm-context) Use this page as compact context for AI coding tools that help build Enterprise API integrations. It is intentionally explicit about what the API does and what tools must not assume. ## Base facts [#base-facts] | Item | Value | | ------------------- | -------------------------------------------------------------------------------------- | | Production base URL | `https://enterprise.spacemedia.uk` | | Staging base URL | `https://staging.spacemedia.uk` | | Auth model | Exchange organization API key and secret for a bearer token with `POST /api/v1/token`. | | Protected requests | Send the bearer token in the `Authorization` header. | | Scope | Authenticated organization only. Do not send organization selectors. | | Public spec | `https://docs.spacemedia.uk/delivery-api/openapi.json` | | Response model | `success`, optional `message`, `data`, optional `meta`, optional `errors`. | ## Endpoint families [#endpoint-families] * Auth and current profile. * Account settings. * Artists, releases, tracks, rights, distribution, readiness, and submission. * Revenue splits. * Users, members, roles, and permissions. * Packages, plans, subscriptions, checkouts, credits, and payment methods. * Add-ons and add-on status. * Copyright summary, wallet reads, top-ups, and release reads. * Release review queues. * Smartlinks, destinations, analytics, and preferences. * Theme and email theme actions. * DDEX connections, messages, and validation. * Signed enterprise webhooks, test deliveries, and replay. * WordPress OAuth installation, authorization, and catalog reads. * Feedback. * Countries and territories. ## Public reference rules [#public-reference-rules] Use public reference fields returned by the API: * `user_id` * `role_id` * `artist_id` * `release_id` * `track_id` * `audio_file_id` * `checkout_id` * `subscription_id` * `smartlink_id` * `review_id` Do not invent internal selectors or rely on generic `id` fields unless the endpoint specifically documents one. Do not expose internal numeric references. ## Workflow order for release delivery [#workflow-order-for-release-delivery] 1. Create or reuse artists. 2. Create the release. 3. Upload audio. 4. Create tracks with `audio_file_id`. 5. Attach or reorder tracks. 6. Save license, rights, territories, and distribution selections. 7. Run release readiness checks. 8. Submit the release. 9. Poll review and delivery states. Do not submit before metadata, rights, artwork, tracks, and destinations are complete. ## Pagination [#pagination] Paginated responses include `meta`. Clients should read: * `current_page` * `last_page` * `per_page` * `total` * `from` * `to` Stop pagination when `current_page` reaches `last_page`, or when the next page returns no data. ## Retry and idempotency [#retry-and-idempotency] * Retry reads with backoff. * Do not auto retry create, checkout, submit, install, top-up, or publish actions after timeout. * Read current state before repeating high-impact operations. * There is no global idempotency key unless an endpoint page says so. * Treat `audio_file_id` as temporary upload data. * Treat `embedded_checkout_token` as short-lived payment data. ## Webhooks [#webhooks] Signed enterprise webhooks exist and are documented. See [Webhooks](/delivery-api/webhooks) for the subscription lifecycle, signature verification, and retry schedule, and the Enterprise Webhooks endpoint group for the operations themselves. Webhook routes are gated on the Enterprise Delivery API add-on, so confirm the organization has them before assuming delivery. Where an organization has no webhook subscription, fall back to the documented polling endpoints. ## Forbidden assumptions [#forbidden-assumptions] AI tools must not: * Add organization selectors to public requests. * Use internal numeric references. * Invent endpoints that are not in the OpenAPI spec. * Rename public references into generic fields. * Log API secrets, bearer tokens, payment tokens, or webhook secrets. * Assume all destinations share the same delivery behavior. * Assume `sent` means live on every DSP. * Assume checkout creation is safe to retry automatically. * Assume acting-for-user behavior applies to every endpoint. * Use backend, database, queue, or storage implementation terms in customer-facing docs. ## Good support data [#good-support-data] When generating support messages or logs, include: * Endpoint and HTTP method. * Public reference. * Timestamp and timezone. * Status code. * Sanitized error body. * Client version. Do not include secrets or provider payment references. # Metadata Style Guide (/delivery-api/metadata-style-guide) Good metadata is not cosmetic. It controls how a release appears on DSPs, whether review can approve it, and whether delivery can proceed without manual repair. Use this page before creating releases and tracks through the API. ## Core rule [#core-rule] Send clean, structured metadata in the correct fields. Do not hide artist roles, versions, territories, rights, or promotional text inside titles or notes. ## Release metadata [#release-metadata] | Area | Rule | Common blocker | | ------------ | -------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------- | | Title | Use the public release title exactly as it should appear. | Extra promo text, internal codes, or store names in the title. | | Version | Put remix, live, radio edit, instrumental, or clean version details in the version field when available. | Version text duplicated in both title and version fields. | | Format | Choose the correct release format such as single, EP, or album. | Sending an album as a single to skip required track order checks. | | Label | Use the label name that owns or represents the release. | Using a distributor name when the release should show a label. | | Language | Use the primary metadata language. | Mixing language display names and codes in the same integration. | | Genre | Use supported genre values from the reference endpoints or endpoint schema. | Free-text genre values that do not match supported options. | | Release date | Use a realistic future live date when delivery lead time matters. | Submitting too close to the intended live date. | | Territories | Send the intended territory list and keep exclusions explicit. | Assuming worldwide delivery when only selected territories were sent. | ## Artist and contributor metadata [#artist-and-contributor-metadata] | Role | Use for | Blocker to avoid | | --------------- | ------------------------------------------------- | ----------------------------------------------------------------------------------- | | Primary Artist | Main artist credited on the release or track. | Putting all contributors into one artist name. | | Featured Artist | Guest artists that should be credited separately. | Writing "feat." only in the title when structured artists are available. | | Composer | Music composition credit. | Omitting composer data on tracks that require writer metadata. | | Writer | Lyric or composition writer. | Reusing the label name as a writer. | | Producer | Production credit where supported. | Treating producer as the primary artist unless they are publicly credited that way. | | Remixer | Remix credit where supported. | Putting remix credit only in the track title. | Endpoint pages remain authoritative for exact accepted role values. Keep role values consistent inside one integration. See [Reference Values](/delivery-api/reference-values) for discovery rules. ## Track metadata [#track-metadata] Every track should have: * `title` * `release_id` * `audio_file_id` from a successful upload * At least one primary artist * Required contributor and writer credits * Language * Genre where required * Rights holder name and year * ISRC when already assigned * Explicit flag when the audio or lyrics require it Track order matters. Set final order before submitting the release. ## Identifiers [#identifiers] | Identifier | Rule | | ---------- | ---------------------------------------------------------------------------------------------- | | UPC | Use the release UPC when you already have one. Do not reuse one UPC across unrelated releases. | | ISRC | Use one ISRC per recording. Do not reuse an ISRC for a different recording, edit, or remix. | | ISWC | Use only when known and applicable. | If SpaceMedia assigns or normalizes identifiers for your workflow, store the returned value and reuse the public release or track reference for API calls. ## Explicit and clean versions [#explicit-and-clean-versions] * Mark explicit content accurately at release and track level where available. * Create separate clean versions when a clean recording is delivered. * Do not label a track as clean if only the metadata title was changed. * Keep explicit and clean versions linked in your own catalog when they represent related recordings. ## Artwork [#artwork] Release artwork should be: * Square. * Production quality. * An original JPG or PNG when the release will be delivered. WEBP can be accepted by upload validation but is not a delivery master. * Between 3000x3000 and 5000x5000 pixels when using release create or update validation. * Free of URLs, store badges, pricing text, barcodes, and temporary promo copy. * Matched to the release title and primary artist. Use multipart form data when uploading `cover_art` through release create or update requests. ## Audio [#audio] Upload the final mastered audio file, then use the returned `audio_file_id` when creating the track. See [Uploads](/delivery-api/uploads) for accepted formats, size limits, duration requirements, chunking, and retry behavior. Operational rules: * Do not create the track until the upload has returned `audio_file_id`. * Keep your local file checksum and filename for retry diagnosis. * Do not reuse an `audio_file_id` for a different recording. * If upload fails, retry the same file before creating another track. * If the track has already been created, use the returned `track_id` for later API calls. ## DSP-specific notes [#dsp-specific-notes] | Destination | Integration note | | ------------- | ------------------------------------------------------------------------------------------------------------------------------------- | | Spotify | Keep artist roles structured. Do not rely on title text for featured artist display. | | Apple Music | Metadata quality, title casing, artwork, and contributor data are strict review factors. | | YouTube Music | YouTube Music and Content ID workflows may require extra rights clarity. Do not assume both are enabled by one generic channel value. | | TikTok | Short-form destinations can have territory, rights, or preview behavior that differs from streaming DSPs. | | Beatport | Genre, label, and electronic music metadata can be more important than generic DSP fields. | Destination-specific behavior can change. Use readiness checks and delivery status pages before assuming a destination accepted a release. ## Pre-submission checklist [#pre-submission-checklist] * Release title, version, artist, label, format, genre, language, and territories are complete. * Artwork is square, production quality, and passes size validation. * Every track has uploaded audio and a stable `track_id`. * Track order is final. * Primary artists and contributors are structured. * Rights holder name and year are present where required. * UPC, ISRC, and ISWC values are correct when supplied. * Explicit flags are accurate. * Distribution channels are selected. * Readiness checks return no blocking issue. Fix metadata before submission. After submission, some fields can become locked or require review before changes are accepted. ## Common questions [#common-questions] **Why was my release rejected for artwork?** Almost always size, shape, or overlaid text. Artwork must be square, within the documented pixel range, and free of URLs, pricing, store badges, and promo text. **Do I need an ISRC before I submit?** Supply one when you own it. Where the platform issues identifiers, do not invent placeholder values, and never reuse an identifier across recordings. **Can I fix metadata after submission?** Depends on the review state. While a release is in review, avoid metadata changes unless the endpoint allows them. See [Delivery Statuses](/delivery-api/delivery-statuses). **What causes the most avoidable rejections?** Contributor credits. At least one Primary Artist is required on a release, and tracks need both a Primary Artist and a Composer credit. # Pagination and Filtering (/delivery-api/pagination-filtering) Collection endpoints return a `data` array and, when paginated, a `meta` object. ```json { "success": true, "data": [ { "release_id": "7f6d2a4b-8c41-4e2d-9c5e-13a2b7c8d904", "title": "Midnight Atlas", "status": "draft" } ], "meta": { "current_page": 1, "last_page": 1, "per_page": 20, "total": 1, "from": 1, "to": 1 } } ``` The staging-only DDEX and enterprise webhook collection endpoints currently use a different envelope. Their top-level `data` value is the paginator, records are in `data.data`, and page fields such as `current_page`, `last_page`, `per_page`, and `total` are siblings of that inner record array. ```json { "data": { "current_page": 1, "data": [ { "reference": "3bc1f628-60af-4db2-b984-321c1525df20", "status": "testing" } ], "last_page": 1, "per_page": 10, "total": 1 } } ``` Use the envelope shown by each operation rather than assuming the nesting is identical across endpoint families. ## Common query fields [#common-query-fields] | Field | Meaning | | -------- | ----------------------------------------------------------------------------------------------------- | | `page` | Page number to return. | | `size` | Records per page. Values below 1 become 1 and values above 100 become 100. Defaults vary by endpoint. | | `search` | Search term for visible records. | | `sort` | Sort direction, usually `asc` or `desc`. | | `status` | Release status filter where the endpoint documents it. | ## Query field matrix [#query-field-matrix] | Endpoint family | Common query fields | | ---------------------------------------------------------------------------- | ----------------------------------------------------------------------------- | | Releases | `page`, `size`, `search`, `status`, `sort` | | Artists, tracks, users, labels, members, packages, subscriptions, smartlinks | `page`, `size`, `search`, `sort` when listed in the endpoint reference | | Release review queues | `page`, `size`, `search`, review status fields shown on that endpoint | | Billing, copyright wallet, and checkout history | Date, status, or gateway filters only where the endpoint reference lists them | ## Client behavior [#client-behavior] * Treat missing `meta` as a non-paginated response. * Use `page` values of 1 or greater and read the returned `per_page`; do not assume every endpoint has the same default. * Request no more than 100 records per page. * Stop fetching when `current_page` equals `last_page`. * Preserve the same `search`, `status`, and `sort` values across pages. * Do not infer access from totals. Permission rules can change what each user sees. ## Common questions [#common-questions] **Why does one endpoint family nest its records differently?** The staging-only DDEX and enterprise webhook collections return the paginator as the top-level `data` value, with records in `data.data`. Read the envelope each operation documents rather than assuming one shape site-wide. **What is the maximum page size?** 100\. Values above it are clamped down and values below 1 are clamped up to 1. Defaults vary per endpoint, so read the returned `per_page`. **How do I know I have reached the last page?** Stop when `current_page` equals `last_page`. A missing `meta` object means the response is not paginated. **Can I use `total` to check what a user can access?** No. Permission rules change what each user sees, so totals are not an access signal. # Rate Limits and Retries (/delivery-api/rate-limits-retries) Enterprise integrations should assume that every API call can fail, time out, or complete after the client has already lost the connection. The safest client is state-driven: it reads the current resource state before repeating high-impact actions. ## Baseline client rules [#baseline-client-rules] | Situation | Required client behavior | | ---------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | | Read request fails with `408`, `429`, or `5xx` | Retry with exponential backoff and jitter. | | Token request fails | Request a new token only when the previous request clearly failed or the token is expired. | | Create request times out | Search or fetch by the business data you already sent before creating another record. | | Upload request fails before a response | Retry the same file or chunk. Use the returned `audio_file_id` only after a successful upload response. | | Submit request times out | Fetch the release and review state before submitting again. | | Checkout request times out | Check whether a `checkout_id` was returned or whether the related order state changed before creating another checkout. | | Add-on install or purchase times out | Read the add-on status before repeating the action. | ## Rate limit handling [#rate-limit-handling] The API can return `429` when a client sends too many requests or repeats expensive operations too quickly. Protected API requests use all of these rolling one-minute limits: | Dimension | Limit | | -------------- | -------------- | | API client | 600 requests | | Organization | 1,200 requests | | Source address | 180 requests | The first exhausted limit stops the request. DDEX requests additionally allow 300 requests per client and 120 per connection each minute. Direct audio uploads allow 10 requests per user, 100 per organization, and 20 per source each minute. Chunk uploads allow 90, 900, and 180 respectively. Token exchange has tighter credential and source limits to resist guessing attacks. When you receive `429`: 1. Stop sending the same request immediately. 2. If the response includes `Retry-After`, wait at least that long. 3. If no retry value is included, wait with exponential backoff. 4. Keep request bursts below the level that caused throttling. 5. Prefer list endpoints and batch-friendly workflows over tight per-record polling loops. Recommended backoff: | Attempt | Minimum wait | | ------------- | ---------------------------- | | First retry | 2 seconds | | Second retry | 5 seconds | | Third retry | 15 seconds | | Later retries | 30 to 60 seconds with jitter | If an integration needs sustained high-volume ingestion, agree the expected volume during onboarding instead of relying on aggressive retry loops. ## Retry safety by operation type [#retry-safety-by-operation-type] | Operation type | Auto retry? | Why | | --------------------------------------------------------- | ----------- | -------------------------------------------------------------------------------------------------------------- | | `GET` list or view | Yes | Reads do not create duplicate catalog, billing, or access changes. | | `POST /api/v1/token` | Conditional | Safe when the previous token is expired or unavailable. Store only the latest usable token. | | Create artist, user, release, track, member, smartlink | No | A repeated request can create duplicate records unless the endpoint explicitly documents duplicate prevention. | | Update metadata | Conditional | Retry only when the same update can be safely applied again and no conflicting operator change happened. | | Upload audio or documents | Conditional | Retry the same file or failed chunk. Do not attach an `audio_file_id` until upload success is confirmed. | | Release submit | No | Read release and review state before retrying. Submission can lock or move the release into review. | | Checkout creation | No | A repeated request can create duplicate payment attempts. Store and verify `checkout_id`. | | Wallet top-up | No | Read checkout or wallet transaction state before creating another payment attempt. | | Add-on purchase, install, activate, deactivate, uninstall | No | Read add-on state before repeating. | | Theme publish or email theme publish | Conditional | Retry only after reading the current published state. | ## Idempotency keys [#idempotency-keys] There is no global idempotency key documented for every endpoint. If an endpoint supports an idempotency key, the endpoint reference must say so directly. Until then: * Generate a client-side operation reference in your own system. * Store the request body, timestamp, acting user, and target public reference. * On timeout, read the target resource before retrying. * For create actions, search for a matching record before creating another one. * For checkout actions, keep the first `checkout_id` and verify it instead of creating a second checkout. ## Polling guidance [#polling-guidance] Polling should be slow, bounded, and state-aware. | Workflow | Suggested polling pattern | | ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------- | | Release readiness | Poll only after metadata or asset changes. Stop once no blocking issue remains. | | Submitted release review | Poll release review queues every 30 to 60 seconds while an operator is waiting. Use longer intervals for background sync. | | Delivery status | Poll sent or delivered release queues every few minutes. Delivery can depend on downstream systems and should not be treated as instant. | | Checkout verification | Poll after user returns from checkout or when a payment screen reports a pending state. | | Upload processing | Poll only when the upload endpoint or follow-up endpoint returns a pending state. | ## Support escalation data [#support-escalation-data] When retry behavior is unclear, provide support with: * Endpoint and HTTP method. * Public reference such as `release_id`, `track_id`, `checkout_id`, or `user_id`. * Request timestamp and timezone. * Response status and message. * Whether the request was retried. * Whether the related resource changed after the timeout. Do not send API secrets, bearer tokens, payment provider references, or raw customer credentials in support messages. ## Common questions [#common-questions] **Which limit did I hit?** The first one exhausted stops the request: 600 per minute per API client, 1,200 per organization, or 180 per source address. DDEX, upload, and token endpoints have their own tighter limits. **Is there an idempotency key?** Not globally. If an endpoint supports one, its endpoint page says so. Until then, read the target resource before repeating a write. **My create request timed out. Should I send it again?** No. Search for a matching record first. A blind retry is the most common cause of duplicate releases and duplicate payment attempts. **How aggressively can I poll?** As slowly as your workflow tolerates. Tight per-record polling loops are the fastest way to hit a rate limit; prefer list endpoints. **I need sustained high-volume ingestion. What now?** Agree the expected volume during onboarding rather than building an aggressive retry loop around the limits. # Reference Values (/delivery-api/reference-values) Enterprise clients should not hardcode every selectable value. Use reference endpoints, endpoint schemas, and response values to keep customer tools aligned with the organization configuration. ## Discovery order [#discovery-order] 1. Use documented reference endpoints such as `GET /api/v1/countries` for country and territory data. 2. Use list endpoints that return allowed roles, packages, plans, add-ons, and member permissions. 3. Use endpoint schemas for request fields that have a fixed public contract. 4. Store the public value returned by the API, not the dashboard display label. ## Values clients commonly need [#values-clients-commonly-need] | Area | Where to discover it | Client behavior | | -------------------------- | ---------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- | | Countries and territories | `GET /api/v1/countries` | Store the returned public code or value expected by the target endpoint. | | Member roles | `GET /api/v1/member-roles` | Store `role_id` for user, member, and permission workflows. | | Member permissions | `GET /api/v1/member-permissions` | Store permission keys only when editing role permissions. | | Packages and subscriptions | Package, plan, and subscription endpoints | Store `package_id`, `plan_id`, and `subscription_id`. | | Add-ons | Values supplied during organization onboarding and the add-on endpoint paths | Store the assigned public add-on slug and version. There is currently no public add-on discovery endpoint. | | Smartlink platforms | Smartlink response and request schemas | Store platform codes such as `spotify` or `apple_music` as documented by the endpoint. | | Review statuses | Release review responses | Display the returned `review_status` and tolerate new values. | | Delivery statuses | Release review and delivery responses | Display the returned `delivery_status` and tolerate new values. | ## Documented release examples [#documented-release-examples] These values appear in public examples and are useful for smoke tests: | Type | Example values | | ------------------- | ---------------------------------------------------------------------- | | Release format | `single`, `ep`, `album` | | Artist role | `Primary Artist`, `Featured Artist`, `Composer`, `Producer`, `Remixer` | | Destination channel | `spotify`, `apple_music`, `youtube_music` | | Genre | `Electronic`, `Ambient` | | Language | `English`, `en` | | Territory | `GB`, `US` | Endpoint pages remain authoritative for exact accepted request values. If an endpoint expects a display label in one field and a code in another, follow that endpoint. ## Status handling [#status-handling] Clients must not crash on a status value they do not recognize. Recommended behavior: * Display the raw returned value. * Store the timestamp of the first observation. * Keep the record visible to operators. * Log the endpoint and public reference for mapping updates. * Avoid irreversible automation for unknown states. See [Delivery Statuses](/delivery-api/delivery-statuses) for release workflow state families. ## Public reference rule [#public-reference-rule] Values that identify an object always use that object's own public reference, such as `release_id` or `checkout_id`. Store them exactly as returned and do not flatten them into a generic identifier column in your own system. The full list is in [Response Conventions](/delivery-api/example-data). ## Common questions [#common-questions] **Can I cache reference data?** Yes, and you should. Countries, roles, and permissions change rarely. Refresh on a schedule rather than on every request, and refresh immediately if a request fails validation on a value you cached. **Should I store the display label or the code?** The value the API returns. Dashboard labels can change without the underlying value changing. **What if an endpoint expects a label in one field and a code in another?** Follow that endpoint page. It is authoritative for its own request body. # Release Lifecycle (/delivery-api/release-lifecycle) The release lifecycle is the main catalog workflow for API integrations. Before implementing this flow, review the [Reference Values](/delivery-api/reference-values), [Uploads](/delivery-api/uploads), [Metadata Style Guide](/delivery-api/metadata-style-guide), [Delivery Statuses](/delivery-api/delivery-statuses), and [Rate Limits and Retries](/delivery-api/rate-limits-retries). These pages prevent the most common production blockers: bad metadata, duplicate submissions, unsafe polling, and unclear delivery states. ## Recommended sequence [#recommended-sequence] 1. Create or reuse artist profiles. 2. Create the release shell with `title`, `cover_art`, `format`, and `artists`. 3. Upload audio and keep the returned `audio_file_id`. 4. Create tracks with `title`, `audio_file_id`, `artists`, `language`, `primary_genre`, credits, ISRC/ISWC, rights holder, and audio links. 5. Attach or reorder tracks on the release. 6. Update license metadata and territories. 7. Update distribution channels. 8. Run release review checks. 9. Submit the release when no blocking issues remain. ## Minimal flow [#minimal-flow] Every catalog write below needs `X-User-Id`, the public `user_id` of the same-organization user the record belongs to. Without it the API returns `403`. See [Acting for Users](/delivery-api/acting-for-users) for the full list and the read endpoints where the header is optional. ```bash curl --request POST 'https://enterprise.spacemedia.uk/api/v1/artists' \ --header 'Authorization: Bearer 0000000000000000000000000000000000000000963fbb8e' \ --header 'X-User-Id: 9d7046b2-3ab1-4c9d-9bd8-90bbd22b7df2' \ --header 'Content-Type: application/json' \ --data '{"name":"Nova Vale","spotify_id":"3q7HBObVc0L8jNeTe5Gofh"}' ``` ```bash curl --request POST 'https://enterprise.spacemedia.uk/api/v1/releases' \ --header 'Authorization: Bearer 0000000000000000000000000000000000000000963fbb8e' \ --header 'X-User-Id: 9d7046b2-3ab1-4c9d-9bd8-90bbd22b7df2' \ --form 'title=Midnight Atlas' \ --form 'format=single' \ --form 'label=Night Shift Records' \ --form 'genre=Electronic' \ --form 'language=English' \ --form 'artists[0][artist_id]=6f209ac7-d82c-4c8f-9d3e-bfe39c0df802' \ --form 'artists[0][type]=Primary Artist' \ --form 'cover_art=@midnight-atlas-cover.jpg;type=image/jpeg' ``` ```bash curl --request POST 'https://enterprise.spacemedia.uk/api/v1/tracks/upload' \ --header 'Authorization: Bearer 0000000000000000000000000000000000000000963fbb8e' \ --header 'X-User-Id: 9d7046b2-3ab1-4c9d-9bd8-90bbd22b7df2' \ --form 'track=@midnight-atlas-master.wav;type=audio/wav' ``` Use the returned `audio_file_id` when creating the track. Reserve `track_id` for the stable track reference returned after track creation. ```bash curl --request POST 'https://enterprise.spacemedia.uk/api/v1/tracks' \ --header 'Authorization: Bearer 0000000000000000000000000000000000000000963fbb8e' \ --header 'X-User-Id: 9d7046b2-3ab1-4c9d-9bd8-90bbd22b7df2' \ --header 'Content-Type: application/json' \ --data '{ "title": "Midnight Atlas", "release_id": "b7a15d95-58f6-4f67-b5d1-89f4f5bfb4d8", "audio_file_id": "audio_1783157400_6f9c2b8e4d1a", "artists": [ { "artist_id": "6f209ac7-d82c-4c8f-9d3e-bfe39c0df802", "type": "Primary Artist" }, { "artist_id": "28636f32-61a4-41b8-8af4-70813049b9aa", "type": "Composer" } ], "language": "English", "license_holder_year": 2026, "license_holder_name": "Night Shift Records Ltd", "links": ["https://media.spacemedia-docs.invalid/audio/midnight-atlas/master.wav"] }' ``` For the release create request, send multipart form data when uploading `cover_art`. The `artists` field takes public `artist_id` values, and every entry needs a `type` from the [artist role list](/delivery-api/reference-values). Roles are display labels, so send `Primary Artist`, not `primary`. At least one entry must be `Primary Artist` or the request is rejected. `title` and `label` are capped at 64 characters. `label`, `genre`, `language`, `format`, and `cover_art` are all required alongside `title` and `artists`. The release date is not set here: save it as `digital_release_date` on the license request below. Readiness checks on `GET /api/v1/releases/{release_id}/pre-qc` are pre-submission validation. Release review queues under `/api/v1/qc/releases/*` are for permitted admins who already have dashboard access to review submitted releases. ## Complete release handoff [#complete-release-handoff] After release and track creation, save rights, distribution, readiness, and submission in this order. ```bash curl --request POST 'https://enterprise.spacemedia.uk/api/v1/releases/b7a15d95-58f6-4f67-b5d1-89f4f5bfb4d8/license' \ --header 'Authorization: Bearer 0000000000000000000000000000000000000000963fbb8e' \ --header 'Content-Type: application/json' \ --data '{ "price_category": "mid", "digital_release_date": "2026-08-21", "original_release_date": "2026-08-21", "license_type": "copyright", "license_holder_year": 2026, "license_holder_name": "Night Shift Records Ltd", "sound_recordings_copyright_year": 2026, "sound_recordings_copyright_name": "Night Shift Records Ltd", "territories": ["GB", "US", "DE", "NL"] }' ``` ```bash curl --request POST 'https://enterprise.spacemedia.uk/api/v1/releases/b7a15d95-58f6-4f67-b5d1-89f4f5bfb4d8/distribution' \ --header 'Authorization: Bearer 0000000000000000000000000000000000000000963fbb8e' \ --header 'Content-Type: application/json' \ --data '{ "channels": ["spotify", "apple_music", "youtube_music"], "territories": ["GB", "US", "DE", "NL"] }' ``` ```bash curl 'https://enterprise.spacemedia.uk/api/v1/releases/b7a15d95-58f6-4f67-b5d1-89f4f5bfb4d8/pre-qc' \ --header 'Authorization: Bearer 0000000000000000000000000000000000000000963fbb8e' ``` Read the readiness response before submission: | Response area | Client action | | ------------------------- | ---------------------------------------------------------------------------------------- | | Blocking metadata issue | Fix release or track metadata, then run readiness again. | | Blocking cover issue | Upload corrected cover art, then run readiness again. | | Blocking audio issue | Upload corrected audio and update the track, then run readiness again. | | Rights or territory issue | Save license and distribution again, then run readiness again. | | No blocking issue | Let an operator submit, or submit from the integration if that is the approved workflow. | ```bash curl --request POST 'https://enterprise.spacemedia.uk/api/v1/releases/b7a15d95-58f6-4f67-b5d1-89f4f5bfb4d8/submit' \ --header 'Authorization: Bearer 0000000000000000000000000000000000000000963fbb8e' ``` After submission, store `release_id`, `review_id` when returned, `review_status`, `delivery_status`, and `submitted_at`. If the submit request times out, fetch the release and review state before sending submit again. On staging, complete the same submission and review sequence. Approval is simulated locally and never reaches a DSP. Store and inspect `delivery_simulated`; a value of `true` confirms a staging contract rehearsal, not storefront availability. Staging release media expires after the documented retention period, so integrations should keep their own fixture files. ## Submission guardrails [#submission-guardrails] * Cover art should be square and production quality. * At least one Primary Artist is required. * Tracks should include required contributor and rights metadata. * Distribution channels should use supported channel codes such as `spotify`, `apple_music`, and `youtube_music`. * Submit only after release review returns no blocking issues. * After a timeout, fetch the release and review state before submitting again. * Treat `sent` as delivery progress, not guaranteed live availability on every DSP. ## Common questions [#common-questions] **Where do most integrations go wrong?** Two places. Attaching an `audio_file_id` before the upload confirmed success, and resubmitting after a timeout without first reading the release and review state. **Can I skip the readiness check and submit directly?** The call will fail on anything blocking, but you lose the itemized list of what to fix. Run `pre-qc` first and let it tell you. **Which reference do I keep?** `release_id` and `track_id`. `audio_file_id` is temporary and only valid until the track is created. **What is the difference between `pre-qc` and the review queues?** `pre-qc` is your own pre-submission validation. The `/api/v1/qc/releases/*` queues are for permitted admins reviewing releases that have already been submitted. **Does an approved release mean it is live?** No. Approval moves it into delivery. See [Delivery Statuses](/delivery-api/delivery-statuses). # SDK Generation (/delivery-api/sdk-generation) The Enterprise API is documented with an OpenAPI contract that can be used to generate internal or customer-specific clients. Official SDK packages should follow the same public contract and naming rules as the API documentation. SDK authors should also read [Rate Limits and Retries](/delivery-api/rate-limits-retries), [Delivery Statuses](/delivery-api/delivery-statuses), and [LLM Context](/delivery-api/llm-context). Generated clients should protect customers from duplicate writes and unsafe assumptions. ## Contract rules [#contract-rules] * Use the published OpenAPI file as the source of truth. * Keep operation names stable and descriptive. * Preserve public reference fields such as `user_id`, `role_id`, `artist_id`, `release_id`, `track_id`, `checkout_id`, `smartlink_id`, and `review_id`. * Do not expose numeric record references, organization references, provider payment references, or duplicate `id` and `uuid` fields. * Treat `embedded_checkout_token` as short-lived payment data and never as a durable checkout reference. * Treat `audio_file_id` as a temporary upload reference. Use the returned `track_id` after creating a track. ## Client behavior [#client-behavior] * Send `Authorization: Bearer ...` on every protected request. * Retry only idempotent reads automatically. For create, checkout, submit, publish, install, and top-up actions, retry only after checking the returned state. * Parse `errors` on `422` responses and return field-level validation feedback to operators. * Read `meta.current_page`, `meta.last_page`, `meta.per_page`, and `meta.total` on paginated responses. * Keep `X-User-Id` support explicit and limited to supported same-organization catalog workflows. ## Customer generation [#customer-generation] Customers can generate their own client from the published OpenAPI file. Pin the downloaded spec in your build so SDK behavior changes only when your team intentionally updates it. ```bash curl --output spacemedia-enterprise-openapi.json \ 'https://docs.spacemedia.uk/delivery-api/openapi.json' ``` Recommended generator settings: | Area | Recommendation | | --------------- | ---------------------------------------------------------------------------------------- | | Operation names | Preserve `operationId` values from the spec. | | Unknown fields | Keep unknown response fields accessible so new non-breaking fields do not break clients. | | Errors | Map API error envelopes to typed exceptions or result objects. | | Pagination | Expose `data` and `meta` together. | | Uploads | Support multipart requests for audio, chunked audio, cover art, and document uploads. | | Retries | Disable automatic retries for writes unless the SDK first reads current state. | | Tokens | Store bearer tokens securely and refresh before expiry. | ## SDK readiness checklist [#sdk-readiness-checklist] | Area | Expectation | | ---------------- | ----------------------------------------------------------------------------------------------------- | | Authentication | Token exchange, token expiry, and bearer header handling are implemented. | | Errors | `401`, `403`, `404`, `409`, and `422` are mapped to useful client exceptions or result objects. | | Pagination | Collection helpers expose pagination metadata and stop conditions. | | Uploads | Audio upload helpers return `audio_file_id`; track creation helpers return `track_id`. | | Checkouts | Hosted and embedded checkout helpers store `checkout_id` and protect `embedded_checkout_token`. | | Release workflow | Artist, release, track, license, distribution, readiness, and submit helpers preserve workflow order. | | Naming | Public field names match the examples in this documentation. | ## Common questions [#common-questions] **Which contract should I generate from?** The published [OpenAPI specification](/delivery-api/openapi.json) only. Do not hand-edit a generated client to work around a contract you disagree with; report the mismatch instead. **Should the SDK rename fields to match my language conventions?** Keep the public reference names intact in the wire model. Renaming `release_id` to something generic is how integrations lose the ability to reconcile with support. **How should a generated client handle unknown enum values?** Pass them through. Strict enums break on the next compatible addition. **Should the SDK retry automatically?** Reads yes, writes no. See [Rate Limits and Retries](/delivery-api/rate-limits-retries) for retry safety by operation type. # Staging Environment (/delivery-api/staging-environment) Use `https://staging.spacemedia.uk` for full integration rehearsals with fictional data. Staging uses the same public API routes, authentication model, validation, review flow, add-on lifecycle, and polling fields as production. ## What works [#what-works] * API credential exchange and bearer authentication * Artists, releases, tracks, uploads, rights, territories, and distribution selections * Release readiness checks and submission * Release review, approval, status polling, takedown, redelivery, and metadata updates * Add-on catalog, install, activate, deactivate, and uninstall flows * Billing contract tests that do not require a real production charge Every add-on is free on staging. Installing an add-on creates and updates the normal local license state, but no payment provider is contacted. Guarded QA runs can explicitly select the `test` gateway to simulate activation-trial card authorization. The simulation creates no real charge, stores no provider card identifier, and does not contact a payment provider. Production always rejects this test gateway. ## Delivery simulation [#delivery-simulation] No staging release is ever sent to a DSP or external delivery partner. After the normal review approval step, staging completes the delivery lifecycle locally and returns the same organization-visible state families that a production client polls. Release review objects include: ```json { "review_status": "approved", "delivery_status": "approved", "delivery_simulated": true } ``` `delivery_simulated` is `true` only on staging. It means that the API workflow completed successfully without external delivery. It is never proof that a release is available on a storefront. ## Enterprise DDEX simulation [#enterprise-ddex-simulation] DDEX sandbox connections use a separate isolated simulator. The same authentication, idempotency, validation, review, queue, message, acknowledgement, webhook, and polling contracts remain available, but staging does not probe or transmit to partner endpoints. * Missing licensed DDEX schemas produce `DDEX_SCHEMA_VALIDATION_SIMULATED` as an informational finding. Structural and semantic checks still run, but the result is not official XSD validation. * Connection health checks handled by the simulator return `simulated: true` and `external_probe_performed: false`. * SpaceMedia can run deterministic sandbox conformance and record a `SIM-STAGING-*` evidence reference. * Simulated deliveries reach `acknowledged` locally and expose `delivery_simulated: true` on the canonical message resource. * Licence and retention workflows are rehearsals only. They do not create legal approvals. * Simulated evidence can never approve a live connection. External delivery remains disabled. This lets a client build and test the complete integration for free while keeping every production gate explicit and fail-closed. ## Media retention [#media-retention] Staging media is stored separately from production and is never mixed with live catalog files. Release covers, audio, release documents, and completed local track uploads expire after seven days by default. Upload chunks and unclaimed files have shorter cleanup windows. Orphaned processing files and stale media locks are also removed automatically. Your test client must: * keep a local source copy of every fictional test file; * tolerate an expired staging media URL; * upload the file again when rerunning an old fixture; * avoid using staging as permanent catalog storage. ## Production separation [#production-separation] * Use separate API credentials in staging and production. * Never send production credentials, live catalog, or customer payment data to staging. * Treat staging status as contract evidence only. * Run an explicit production cutover after the [Go-Live Checklist](/delivery-api/go-live-checklist). ## Common questions [#common-questions] **Does a staging release ever reach a store?** No. Staging completes the delivery lifecycle locally and returns the same state families a production client polls. `delivery_simulated: true` marks that result. **Do add-ons cost anything on staging?** No. Every add-on is free there. Installing one creates the normal local license state without contacting a payment provider. **Why did my staging media URL stop working?** Staging media expires. Covers, audio, release documents, and completed local uploads clear after seven days by default, and upload chunks sooner. Keep local copies of your fixtures and re-upload when rerunning an old test. **Can staging evidence approve a live DDEX connection?** No. Simulated evidence is a rehearsal. Every production gate stays explicit and fails closed. # Troubleshooting (/delivery-api/troubleshooting) Use this page when an integration works in a small test but fails during a real customer workflow. Start with the symptom, confirm the likely cause, then use the recovery action before opening a support request. ## Fast triage [#fast-triage] | Symptom | Likely cause | Recovery | | -------------------------------------------- | ----------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- | | Token request fails | API credentials are wrong, inactive, or copied from the wrong organization. | Regenerate credentials from the correct organization admin account and exchange them again. | | Protected endpoint returns `401` | Bearer token is missing, expired, or not sent in the `Authorization` header. | Exchange credentials for a fresh token and retry the protected request once. | | Endpoint returns `403` | The credential owner or acted-for user lacks permission, or the required add-on is not active. | Check user role, member permissions, and add-on access. Do not retry automatically. | | Endpoint returns `404` for a known record | The public reference belongs to a different organization or the wrong reference field was used. | Fetch the record list in the authenticated organization and use the returned public reference. | | Create request appears to duplicate data | Client retried a write after timeout without checking current state. | Search or fetch the matching record before creating another one. | | Release cannot submit | Metadata, rights, artwork, tracks, or destinations are incomplete. | Run readiness checks, fix every blocking issue, then submit once. | | Release status does not change immediately | Review and delivery are asynchronous workflows. | Poll the documented review or delivery endpoint with a bounded interval. | | Checkout completes but access is not updated | Checkout verification was not called or payment is still pending. | Verify the checkout with `checkout_id` and read the related billing or add-on state. | | Upload succeeds but track creation fails | Client did not pass the returned `audio_file_id`, or the release reference is wrong. | Use the `audio_file_id` from the successful upload response and the current `release_id`. | | SDK code compiles but fails at runtime | Generated client renamed public fields or hides response metadata. | Keep public field names and expose `meta`, `message`, `errors`, and public references. | ## Authentication checks [#authentication-checks] 1. Confirm the base URL is `https://enterprise.spacemedia.uk`. 2. Exchange API key and secret with `POST /api/v1/token`. 3. Store the returned bearer token securely. 4. Send the token in the `Authorization` header on protected calls. 5. Refresh before expiry instead of repeatedly retrying failed protected calls. Never send the API secret after token exchange. ## Permission and add-on checks [#permission-and-add-on-checks] If a call returns `403`, check: * The API product is active for the organization. * The authenticated user has access to the workflow. * The acted-for user belongs to the same organization. * The endpoint supports acted-for user context. * The required add-on is active. * The operation is not admin-only when the acting user is a catalog user. Do not work around `403` by adding organization selectors or internal references to the request. ## Catalog delivery checks [#catalog-delivery-checks] Before release submission: 1. Confirm artists exist and use public `artist_id` values. 2. Confirm release metadata is complete. 3. Confirm cover art passes validation. 4. Confirm each uploaded track has an `audio_file_id`. 5. Confirm each created track has a stable `track_id`. 6. Confirm track order is final. 7. Confirm rights, territories, and distribution channels are set. 8. Run readiness checks. 9. Submit only after all blocking issues are fixed. If submission times out, fetch the release and review state before retrying. ## Metadata checks [#metadata-checks] Common metadata causes of review or delivery problems: | Problem | Fix | | ----------------------------------------------------------------- | ------------------------------------------------------------------------- | | Featured artist text is only in the title. | Send featured artists as structured artist roles. | | Remix or clean version is duplicated in title and version fields. | Keep title and version data separate. | | Cover art includes URLs, pricing, or promo text. | Upload clean square artwork that matches the release. | | ISRC is reused for a different recording. | Use one ISRC per recording, edit, remix, or clean version. | | Territories do not match rights. | Send only territories where the customer has delivery rights. | | Explicit content is not marked. | Set explicit flags accurately at release and track level where available. | Use [Metadata Style Guide](/delivery-api/metadata-style-guide) before resubmitting. ## Payment and checkout checks [#payment-and-checkout-checks] For checkout workflows: * Store `checkout_id`. * Treat embedded checkout data as short-lived. * Verify checkout state after the user returns. * Do not create another checkout after a timeout until the first checkout state is known. * Show a clear recovery action for expired, cancelled, or failed checkouts. ## Polling checks [#polling-checks] Polling should stop when it has enough information. | Workflow | Stop polling when | | --------- | --------------------------------------------------------------------------------------- | | Readiness | No blocking issue remains or the operator leaves the edit flow. | | Review | The release has a terminal review state or the integration switches to background sync. | | Delivery | The release is delivered, rejected, failed, or moved into manual handling. | | Checkout | The checkout is completed, failed, cancelled, or expired. | If polling receives `429`, slow down immediately and follow [Rate Limits and Retries](/delivery-api/rate-limits-retries). ## Support packet [#support-packet] Send support only the data needed to investigate: * Endpoint and HTTP method. * Public reference such as `release_id`, `track_id`, `checkout_id`, `user_id`, or `smartlink_id`. * Timestamp and timezone. * Status code. * Sanitized response body. * Client or SDK version. * Retry count and last retry time. * Current resource state after the failure. Do not send API secrets, bearer tokens, webhook secrets, private keys, raw customer credentials, or provider payment references. ## Related pages [#related-pages] # Uploads (/delivery-api/uploads) Upload behavior is one of the highest-risk parts of catalog integration. A client should know when an upload is complete, which reference to store, and what is safe to retry. ## Audio upload limits [#audio-upload-limits] | Rule | Value | | ---------------------------- | ---------------------------------------------------- | | Accepted audio extensions | `wav`, `mp3`, `flac`, `m4a`, `aac`, `aif`, `aiff` | | Maximum audio file size | 500 MB | | Minimum audio duration | 60 seconds | | Required content | A readable audio stream matching the file extension. | | Returned temporary reference | `audio_file_id` | The upload endpoint verifies audio metadata. Files that cannot be read, do not contain audio, do not match their extension, exceed the size limit, or are shorter than the minimum duration fail validation. ## Complete file upload [#complete-file-upload] Use `POST /api/v1/tracks/upload` when the customer system can send the whole file in one multipart request. ```bash curl --request POST 'https://enterprise.spacemedia.uk/api/v1/tracks/upload' \ --header 'Authorization: Bearer 0000000000000000000000000000000000000000963fbb8e' \ --header 'X-User-Id: 9d7046b2-3ab1-4c9d-9bd8-90bbd22b7df2' \ --form 'track=@midnight-atlas-master.wav;type=audio/wav' ``` Every upload route requires `X-User-Id`, including the status read used for recovery. Use the same value for the upload and for the track create that follows it. Store `audio_file_id` from the response and use it when creating the track. Do not treat `audio_file_id` as the stable track reference. ## Chunked upload [#chunked-upload] Use `POST /api/v1/tracks/upload/chunk` when a client needs to send a large file in pieces. | Field | Rule | | ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | | `upload_session_id` | Optional stable client-generated session reference. Send one and use the same value for every chunk so the upload can be resumed safely. | | `chunk_index` | Zero-based chunk number. The first chunk is `0`. | | `total_chunks` | Total number of chunks expected for the file. Maximum 64, so size your chunks to fit the file rather than to a fixed small value. | | `file_name` | Original file name with an accepted audio extension. | | `file_size` | Full file size in bytes. | | `chunk` | Binary chunk file. Each chunk can be up to 8 MB. | The API returns `upload_session_id` and `complete: false` while it is still waiting for more chunks. It returns `complete: true` and `audio_file_id` after every chunk is received, assembled, and validated. With 8 MB chunks and a 64-chunk ceiling, one chunked upload covers a file up to about 512 MB, which matches the 500 MB audio limit. Run at most 3 upload sessions per user and 25 per organization at once; further sessions are rejected until an active one finishes. ## Recover upload status [#recover-upload-status] Call `GET /api/v1/tracks/upload/{upload_session_id}` after a timeout, reconnect, or lost final response. Use the same value that was sent as `upload_session_id`. * When `complete` is `false`, compare `received_chunks` with `total_chunks` and resend only missing chunks. * When `complete` is `true`, store the returned `audio_file_id` and continue with track creation. * A `404` means the session is unknown to the current user and organization, or its recovery window has expired. Start a new upload session. Upload status and completed receipts are scoped to the authenticated user and organization. A different user cannot use this endpoint to discover or claim another user's upload. ## Retry behavior [#retry-behavior] | Failure | Safe action | | --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- | | Complete upload fails before a response | Retry the same file once network health is restored. | | Chunk upload fails before a response | Check upload status, then retry the same chunk with the same `upload_session_id` and `chunk_index` only if it is missing. | | Final chunk returns validation errors | Fix the source file or chunking logic, then start a new upload session. | | Track create fails after upload | Reuse the successful `audio_file_id` if the failure was unrelated to the audio file. | If a client is unsure whether the final chunk completed, query upload status. Do not create a track until the API has returned `audio_file_id`. ## Cover art [#cover-art] Release create and update requests use multipart form data when `cover_art` is uploaded. The upload validator accepts JPG, PNG, or WEBP. Use an original JPG or PNG for a release that will be delivered to stores; a WEBP upload can be accepted by the editor but is not a delivery master. Cover art should be: * Original JPG or PNG for delivery. WEBP is suitable only for non-delivery editing workflows. * Square. * Between 3000x3000 and 5000x5000 pixels where release validation applies. * Free of URLs, pricing, store badges, and temporary promo text. ## Attachment order [#attachment-order] 1. Upload audio. 2. Store `audio_file_id`. 3. Create track with `audio_file_id`. 4. Store returned `track_id`. 5. Attach, order, update, or document the track with `track_id`. See [Release Lifecycle](/delivery-api/release-lifecycle) for the full catalog flow. ## Common questions [#common-questions] **What is the difference between `audio_file_id` and `track_id`?** `audio_file_id` is a temporary reference to an uploaded file. `track_id` is the stable catalog reference returned after the track is created. Never store the first where you mean the second. **When is it safe to create the track?** Only after the API has returned `audio_file_id`. If you are unsure whether the final chunk landed, query upload status first. **My upload session returns `404`. What happened?** The session is unknown to the current user and organization, or its recovery window has expired. Start a new upload session. **Can I upload WEBP cover art for a release going to stores?** Use an original JPG or PNG for delivery. The editor accepts WEBP, but it is not a delivery master. # Versioning (/delivery-api/versioning-changelog) The public API uses the `/api/v1` path. The OpenAPI `info.version` identifies the published contract revision, while `/api/v1` identifies the compatibility line. Clients should pin the OpenAPI revision used to generate or validate their integration and review the [Changelog](/changelog) before each production release. ## Compatibility rules [#compatibility-rules] | Change | Expected client action | | ---------------------------------------------------- | ------------------------------------------------------------------------------------------------------- | | New endpoint or optional request field | No immediate change. Adopt it when useful. | | New response field | Ignore unknown fields and continue processing known fields. | | New enum or status value | Preserve and display the raw value. Do not fail parsing or trigger an irreversible action. | | New validation rule | Read the returned field errors, correct the request, and rerun readiness checks. | | Deprecated field or operation | Move to the documented replacement before the published removal date. | | Breaking request, response, auth, or behavior change | Follow the migration guide and before-and-after example published before the change reaches production. | Clients must not depend on response property order, undocumented fields, dashboard routes, numeric record references, or values that appear only in one example. ## Deprecation notices [#deprecation-notices] A deprecation notice states the affected operation or field, customer impact, replacement, migration action, announcement date, and removal date. When applicable, responses can also include standard `Deprecation`, `Sunset`, and `Link` headers. Treat those headers as operational alerts and surface them in integration monitoring. SpaceMedia does not silently repurpose an existing field with a different meaning. A change that cannot remain compatible requires a migration guide before release. ## Changelog review [#changelog-review] The public changelog includes customer-visible API additions, behavior changes, authentication or capability changes, error and rate-limit changes, webhook event changes, deprecations, and migrations. Weeks containing only internal maintenance are omitted. Before upgrading a generated client: 1. Download the current [OpenAPI contract](/delivery-api/openapi.json). 2. Compare it with the revision pinned by your build. 3. Review changelog entries between the two revisions. 4. Regenerate the client and inspect the diff. 5. Run contract, staging, retry, upload, webhook, and end-to-end release tests. 6. Promote the same tested client build to production. ## Report an unexpected change [#report-an-unexpected-change] Provide the method and path, timestamp with timezone, public resource reference, expected contract revision, sanitized response, and request correlation information when available. Never send credentials, bearer tokens, signing secrets, payment details, or customer files. ## Common questions [#common-questions] **How much notice do I get for a breaking change?** Breaking changes are announced with a migration path and sunset information. Compatible additions can ship at any time, so clients must tolerate new fields and values. **What counts as a compatible addition?** New optional request fields, new response fields, new enum values, and new operations. None of these should break a correctly written client. **Where do I track changes?** The [Delivery API changelog](/changelog/delivery-api), which also has a feed you can subscribe to. **I found undocumented behavior. What should I do?** Report it rather than depending on it. Undocumented behavior is not part of the contract and can change without notice. # Webhooks (/delivery-api/webhooks) Enterprise webhooks are available initially for DDEX operations. They use HTTPS-only endpoints, HMAC-SHA256 signatures, at-least-once delivery, bounded retries, test events, delivery logs, and reveal-once signing secrets. ## Current availability [#current-availability] Enterprise webhook routes follow DDEX availability. They are currently available in staging for receiver testing and conformance. Do not depend on production delivery until SpaceMedia confirms that the production routes and your DDEX connection are active. Webhook bodies stay compact. Fetch the canonical resource URL in each event before making an irreversible decision. ## Available events [#available-events] | Event | Scope | Meaning | | ------------------------------ | ------------------------------ | --------------------------------------------------------------------------------------------- | | `ddex.delivery.status_changed` | DDEX message | Control, transport, or partner processing state changed. | | `ddex.delivery.blocked` | DDEX message | Validation, review, contract, or state checks blocked progress. | | `ddex.delivery.acknowledged` | DDEX message | The partner acknowledged the message. | | `ddex.delivery.rejected` | DDEX message | The partner rejected the message. | | `ddex.delivery.failed` | DDEX message | Retryable transport work exhausted its allowance or a non-retryable transport block occurred. | | `ddex.import.completed` | DDEX import and source message | An atomic create-only import completed. | | `ddex.import.failed` | DDEX import and source message | An import failed without partial catalog creation. | | `ddex.connection.degraded` | DDEX connection | Connection health requires operator attention. | ## Event payload [#event-payload] Every event carries a stable event name, a public resource reference, a canonical API path, and an occurrence time. Fetch the canonical path to obtain current state because the resource can change after the event was created. ```json { "event": "ddex.delivery.status_changed", "resource": { "type": "ddex_message", "reference": "45be9e79-f39e-4cf9-bfc8-bf9f10481da6", "url": "/api/v1/ddex/messages/45be9e79-f39e-4cf9-bfc8-bf9f10481da6" }, "occurred_at": "2026-07-30T15:30:00Z" } ``` A replay adds `replay_of` with the original delivery reference and receives a new `SpaceMedia-Webhook-Id`. The test endpoint sends `enterprise.webhook.test` with the webhook subscription as its resource. Test events do not need to appear in the subscription's event filter. ## Create a subscription [#create-a-subscription] `POST /api/v1/webhooks` requires `webhooks:manage` and an `Idempotency-Key`. ```json { "name": "Catalog operations", "endpoint_url": "https://hooks.northstar-distribution.co.uk/spacemedia", "events": [ "ddex.delivery.status_changed", "ddex.delivery.blocked", "ddex.delivery.acknowledged", "ddex.delivery.rejected" ] } ``` The signing secret is returned once. Store it in a secrets manager. Later reads return only `secret_configured` and the rotation timestamp. ## Verify a delivery [#verify-a-delivery] The request includes: * `SpaceMedia-Webhook-Id`: stable delivery reference for deduplication. * `SpaceMedia-Webhook-Timestamp`: Unix timestamp. * `SpaceMedia-Webhook-Signature`: one or more comma-separated `v1=` HMAC values. Two values are sent during the five-minute secret-rotation overlap. Compute HMAC-SHA256 over: `timestamp + "." + exact_raw_body` Reject the request when the timestamp is more than five minutes away from your server clock or the signature does not match by constant-time comparison. Synchronize receiver clocks with a reliable time source. TypeScript: ```ts import { createHmac, timingSafeEqual } from "node:crypto"; export function verifyWebhook(rawBody: string, timestamp: string, header: string, secrets: string[]) { const received = header.split(",").map((value) => value.trim().replace(/^v1=/, "")); return secrets.some((secret) => { const expected = createHmac("sha256", secret).update(`${timestamp}.${rawBody}`).digest("hex"); return received.some( (value) => expected.length === value.length && timingSafeEqual(Buffer.from(expected), Buffer.from(value)), ); }); } ``` PHP: ```php $received = array_map( fn ($value) => preg_replace('/^v1=/', '', trim($value)), explode(',', $signatureHeader), ); $valid = false; foreach ($activeSecrets as $secret) { $expected = hash_hmac('sha256', $timestamp.'.'.$rawBody, $secret); $valid = $valid || collect($received)->contains( fn ($value) => is_string($value) && hash_equals($expected, $value) ); } if (! $valid) { http_response_code(401); exit; } ``` ## Delivery contract [#delivery-contract] * Delivery is at least once. Store the webhook delivery reference and process duplicates safely. * Event ordering is not guaranteed across retries or subscriptions. * Any `2xx` response marks the attempt as delivered. Other statuses are not successful acknowledgements. * Return a successful response after durable acceptance, then process slow work asynchronously. * Redirects are not followed. * Endpoints must use HTTPS and resolve only to public network addresses. * Payloads are limited to 256 KB. * Connection establishment has a five-second limit and a delivery attempt has a ten-second default limit. * A timeout, connection failure, throttling response, or temporary server response can be retried. * Retry delays are 30 seconds, 2 minutes, 10 minutes, 30 minutes, 1 hour, 2 hours, and 6 hours after the initial attempt. * A failed subscription is not disabled automatically. Pause it explicitly while repairing the receiver. * Inspect attempts through `GET /api/v1/webhooks/{reference}/deliveries`. ## Manage, test, and rotate [#manage-test-and-rotate] Use `PATCH /api/v1/webhooks/{reference}` to update the name, HTTPS endpoint, event set, or active state. Set `active` to `false` to pause delivery while retaining delivery history. Use `DELETE /api/v1/webhooks/{reference}` only when the subscription and its delivery history can be permanently removed. Both mutations require an `Idempotency-Key`. Use `POST /api/v1/webhooks/{reference}/test` before depending on event delivery. The test passes through the normal signing, queue, delivery, and log path. Use `POST /api/v1/webhooks/{reference}/rotate-secret` to replace the secret. The new value is returned once. For five minutes, deliveries include signatures made with both the new and previous secrets. Configure the receiver with both secrets during that overlap, then remove the old secret after `previous_secret_valid_until`. Never copy either secret into source control, logs, tickets, or support messages. Use `POST /api/v1/webhooks/{reference}/deliveries/{deliveryReference}/replay` for an operator-controlled replay. A replay receives a new delivery reference and retains `replay_of` for audit and deduplication. ## Consumer workflow [#consumer-workflow] 1. Verify timestamp and signature against the raw body. 2. Deduplicate by `SpaceMedia-Webhook-Id`. 3. Persist the event and return a success response. 4. Fetch the canonical resource URL with your bearer token. 5. Apply the current resource state idempotently. 6. Keep periodic reconciliation until event delivery is proven for the connection. ## Support escalation data [#support-escalation-data] Provide the subscription reference, delivery reference, event name, timestamp with timezone, HTTP status, and DDEX correlation key. Never send signing secrets, bearer tokens, private keys, or raw credentials. ## Common questions [#common-questions] **Should I trust the payload without verifying the signature?** Never. Signature verification is the only thing separating a real event from anyone who learned your endpoint URL. **How do I rotate a secret without dropping events?** Accept both the old and new secret during the overlap window, then retire the old one once you have seen traffic verified against the new one. **Do I need to be idempotent?** Yes. Retries and replays mean the same event can arrive more than once. Key your processing on the event reference. **My consumer was down. Are those events lost?** Use the delivery attempt and replay tooling to recover rather than reconstructing state by hand. # Workflows (/delivery-api/workflows) Use this page as the sequence map for common integrations. Each workflow lists the calls in the order an integration should usually make them, the reference fields to keep, and the state checks that prevent failed submissions. ## Integration posture [#integration-posture] * Authenticate first with `POST /api/v1/token`, then send `Authorization: Bearer ...` on every request. * Store only public references such as `user_id`, `role_id`, `artist_id`, `release_id`, `track_id`, `checkout_id`, `smartlink_id`, and `review_id`. * Treat `embedded_checkout_token` as short-lived payment data. Do not log it or store it as a durable checkout reference. * Use `X-User-Id` only for supported catalog workflows when an integration needs to act for a user in the same organization. * For list endpoints, read `meta.current_page`, `meta.per_page`, `meta.total`, and `meta.last_page` before scheduling the next page. ## Copy-ready snippets [#copy-ready-snippets] Use these short recipes as starting points for each major endpoint group. Replace only the public references with values returned by earlier API calls. ### Authentication and profile [#authentication-and-profile] ```bash curl --request POST 'https://enterprise.spacemedia.uk/api/v1/token' \ --header 'X-Api-Key: 00000000-0000-4000-8000-000000000000' \ --header 'X-Api-Secret: 0000000000000000000000000000000000000000' curl 'https://enterprise.spacemedia.uk/api/v1/me' \ --header 'Authorization: Bearer 0000000000000000000000000000000000000000963fbb8e' ``` ### Users and members [#users-and-members] ```bash curl 'https://enterprise.spacemedia.uk/api/v1/member-roles' \ --header 'Authorization: Bearer 0000000000000000000000000000000000000000963fbb8e' curl --request POST 'https://enterprise.spacemedia.uk/api/v1/users' \ --header 'Authorization: Bearer 0000000000000000000000000000000000000000963fbb8e' \ --header 'Content-Type: application/json' \ --data '{"email":"eli.brooks@northstar-distribution.co.uk","role_ids":["c0f1c68c-7c2f-4954-b52c-9d7e5eb46d3e"]}' ``` ### Catalog delivery [#catalog-delivery] ```bash curl --request POST 'https://enterprise.spacemedia.uk/api/v1/artists' \ --header 'Authorization: Bearer 0000000000000000000000000000000000000000963fbb8e' \ --header 'X-User-Id: 9d7046b2-3ab1-4c9d-9bd8-90bbd22b7df2' \ --header 'Content-Type: application/json' \ --data '{"name":"Nova Vale","spotify_id":"3q7HBObVc0L8jNeTe5Gofh"}' curl --request POST 'https://enterprise.spacemedia.uk/api/v1/tracks' \ --header 'Authorization: Bearer 0000000000000000000000000000000000000000963fbb8e' \ --header 'X-User-Id: 9d7046b2-3ab1-4c9d-9bd8-90bbd22b7df2' \ --header 'Content-Type: application/json' \ --data '{"title":"Midnight Atlas","release_id":"b7a15d95-58f6-4f67-b5d1-89f4f5bfb4d8","audio_file_id":"audio_1783157400_6f9c2b8e4d1a","artists":[{"artist_id":"6f209ac7-d82c-4c8f-9d3e-bfe39c0df802","type":"Primary Artist"},{"artist_id":"28636f32-61a4-41b8-8af4-70813049b9aa","type":"Composer"}],"language":"English","license_holder_year":2026,"license_holder_name":"Night Shift Records Ltd","links":["https://media.spacemedia-docs.invalid/audio/midnight-atlas/master.wav"]}' ``` ### Billing and checkouts [#billing-and-checkouts] ```bash curl 'https://enterprise.spacemedia.uk/api/v1/billing/overview' \ --header 'Authorization: Bearer 0000000000000000000000000000000000000000963fbb8e' curl --request POST 'https://enterprise.spacemedia.uk/api/v1/order/checkout/verify' \ --header 'Authorization: Bearer 0000000000000000000000000000000000000000963fbb8e' \ --header 'Content-Type: application/json' \ --data '{"checkout_id":"39b189c1-8f8e-4df2-8632-176f87f791a1"}' ``` ### Add-ons [#add-ons] ```bash curl --request POST 'https://enterprise.spacemedia.uk/api/v1/addons/release-smartlinks/checkout' \ --header 'Authorization: Bearer 0000000000000000000000000000000000000000963fbb8e' \ --header 'Content-Type: application/json' \ --data '{"version":"v1.0.0","cycle":"monthly","return_to":"/addons/smartlinks"}' ``` ### Copyright wallet [#copyright-wallet] ```bash curl --request POST 'https://enterprise.spacemedia.uk/api/v1/copyright/wallet/top-up' \ --header 'Authorization: Bearer 0000000000000000000000000000000000000000963fbb8e' \ --header 'Content-Type: application/json' \ --data '{"currency":"EUR","package_code":"eur_100"}' ``` ### Smartlinks [#smartlinks] ```bash curl --request POST 'https://enterprise.spacemedia.uk/api/v1/smartlinks' \ --header 'Authorization: Bearer 0000000000000000000000000000000000000000963fbb8e' \ --header 'Content-Type: application/json' \ --data '{"release_id":"b7a15d95-58f6-4f67-b5d1-89f4f5bfb4d8","slug":"nova-vale-midnight-atlas","title":"Midnight Atlas","links":[{"platform":"spotify","url":"https://open.spotify.com/album/4Gj9kL2mN8rT6bY1xQvP3z","is_visible":true,"sort_order":0}]}' ``` ### Branding and email theme [#branding-and-email-theme] ```bash curl --request POST 'https://enterprise.spacemedia.uk/api/v1/theme-editor/draft' \ --header 'Authorization: Bearer 0000000000000000000000000000000000000000963fbb8e' \ --header 'Content-Type: application/json' \ --data '{"config":{"preset":"default","radius":"md","scale":"sm","contentLayout":"centered","font":"default","brand":"default","accent":"default"}}' ``` ### Feedback [#feedback] ```bash curl --request POST 'https://enterprise.spacemedia.uk/api/v1/platform-feedback' \ --header 'Authorization: Bearer 0000000000000000000000000000000000000000963fbb8e' \ --header 'Content-Type: application/json' \ --data '{"category":"idea","message":"Release import is ready for a webhook callback option.","page_url":"https://enterprise.spacemedia.uk/releases"}' ``` ## User and member setup [#user-and-member-setup] Use the Users API when you need a full artist or catalog user account. Use the Team Members add-on when you need team access, role permissions, invitations, and admin workflows. 1. List role references with `GET /api/v1/member-roles`. 2. Create a user with `POST /api/v1/users`. 3. Store the returned `user_id` and role `role_id` values. 4. For team access, invite members with `POST /api/v1/members/invite`. 5. Confirm invitation state with `GET /api/v1/member-invitations`. 6. Update role permissions only through `POST /api/v1/member-roles/{role_id}/permissions`. ```bash curl --request POST 'https://enterprise.spacemedia.uk/api/v1/users' \ --header 'Authorization: Bearer 0000000000000000000000000000000000000000963fbb8e' \ --header 'Content-Type: application/json' \ --data '{ "email": "eli.brooks@northstar-distribution.co.uk", "role_ids": ["c0f1c68c-7c2f-4954-b52c-9d7e5eb46d3e"] }' ``` The invited user sets their own name when they accept the invitation, so this endpoint takes only the email and the roles. `role_ids` is required whenever the Team Members add-on is active, and each value is a `role_id` from `GET /api/v1/member-roles`. Do not pass organization references in public requests. The organization is resolved from the authenticated API context. ## Release delivery [#release-delivery] Release delivery is a multi-step workflow. Create stable artist and release records first, then upload audio, create tracks against the release, and submit only after metadata, rights, and destinations pass readiness checks. 1. Create or reuse artists with `POST /api/v1/artists`. 2. Create the release shell with `POST /api/v1/releases`. 3. Upload master audio with `POST /api/v1/tracks/upload`. 4. Create tracks with `POST /api/v1/tracks`, using the returned `audio_file_id` and the release `release_id`. 5. Reorder tracks with `POST /api/v1/releases/{release_id}/tracks/reorder` when the release has more than one track. 6. Save rights metadata with `POST /api/v1/releases/{release_id}/license`. 7. Save delivery channels with `POST /api/v1/releases/{release_id}/distribution`. 8. Run readiness checks with `GET /api/v1/releases/{release_id}/pre-qc`. 9. Submit with `POST /api/v1/releases/{release_id}/submit`. 10. Track review queues through `GET /api/v1/qc/releases/submitted`, `GET /api/v1/qc/releases/sent`, or `GET /api/v1/qc/releases/all` when the authenticated user has access. Keep these references: | Returned field | Use | | --------------- | ----------------------------------------------------------------------------------- | | `artist_id` | Credit artists on releases and tracks. | | `audio_file_id` | Temporary uploaded audio reference used when creating a track. | | `track_id` | Stable track reference used for updates, assignments, and document actions. | | `release_id` | Stable release reference used for metadata, delivery, review, and submission calls. | | `review_id` | Release review reference returned when a release enters review. | ## Billing and checkout [#billing-and-checkout] Billing flows return either a redirect URL, an embedded checkout token, or a saved payment method reference. Store the durable public checkout reference, then poll or verify status through the matching endpoint. 1. Read billing state with `GET /api/v1/billing/overview`. 2. Start a subscription checkout, add-on checkout, credit top-up, or payment method setup. 3. Store `checkout_id` with your local order or billing action. 4. If an `embedded_checkout_token` is returned, hand it directly to your payment UI. 5. Redirect users with `redirect_url` only when the response uses hosted checkout. 6. Verify status with the matching status or verify endpoint before unlocking paid features. ```bash curl --request POST 'https://enterprise.spacemedia.uk/api/v1/copyright/wallet/top-up' \ --header 'Authorization: Bearer 0000000000000000000000000000000000000000963fbb8e' \ --header 'Content-Type: application/json' \ --data '{ "currency": "EUR", "package_code": "eur_100" }' ``` Copyright wallet top-ups settle in `EUR` or `USD` only. Package codes follow the currency: `eur_50`, `eur_100`, `eur_250`, `usd_50`, `usd_100`, `usd_250`. Return URLs are not part of this request; use the returned checkout reference and verify status through the matching endpoint. ## Smartlinks [#smartlinks-1] Smartlinks are release landing pages with managed destination links, analytics, and preference controls. 1. Confirm the Smartlink add-on is active. 2. Create a smartlink with `POST /api/v1/smartlinks`. 3. Store `smartlink_id` and `public_url`. 4. Use `PUT /api/v1/smartlinks/{smartlink_id}` for metadata or destination updates. 5. Use `POST /api/v1/smartlinks/{smartlink_id}/sync` after release metadata changes. 6. Read analytics with `GET /api/v1/smartlinks/{smartlink_id}/analytics`. 7. Use preference endpoints to manage user-level and organization-level behavior. ```bash curl --request POST 'https://enterprise.spacemedia.uk/api/v1/smartlinks' \ --header 'Authorization: Bearer 0000000000000000000000000000000000000000963fbb8e' \ --header 'Content-Type: application/json' \ --data '{ "release_id": "b7a15d95-58f6-4f67-b5d1-89f4f5bfb4d8", "slug": "nova-vale-midnight-atlas", "title": "Midnight Atlas", "links": [ { "platform": "spotify", "url": "https://open.spotify.com/album/4Gj9kL2mN8rT6bY1xQvP3z", "is_visible": true, "sort_order": 0 }, { "platform": "apple_music", "url": "https://music.apple.com/gb/album/midnight-atlas/1784529016", "is_visible": true, "sort_order": 1 } ] }' ``` Destinations are sent as `links`. Each entry needs `platform` and `url`; `title`, `source`, `sort_order`, and `is_visible` are optional. `release_id`, `slug`, and `title` on the smartlink itself are all optional, so you can create a standalone landing page that is not tied to a release. ## Copyright wallet and release checks [#copyright-wallet-and-release-checks] Copyright endpoints expose organization-visible wallet balances, transactions, release checks, and top-ups. 1. Read summary with `GET /api/v1/copyright/summary`. 2. Read wallet state with `GET /api/v1/copyright/wallet`. 3. Create a wallet top-up when more credits are required. 4. Poll `GET /api/v1/copyright/wallet/top-up/{checkout_id}/status`. 5. List release checks with `GET /api/v1/copyright/releases`. 6. Open a release check with `GET /api/v1/copyright/releases/{release_id}`. Top-ups and checks are scoped to the authenticated organization. Public responses use `wallet_id`, `top_up_id`, `wallet_transaction_id`, `release_id`, `track_id`, and `copyright_check_id`. ## Branding and communication [#branding-and-communication] Use these APIs when an organization admin needs automation around branding, email appearance, support details, legal pages, and public customer-facing settings. 1. Read current branding or theme profile. 2. Save drafts through the draft endpoint. 3. Preview before publishing. 4. Publish only after the admin has reviewed the rendered result. 5. Use support, terms, privacy, domain, and SSO guides for admin-facing setup rules that are not purely API driven. Branding calls should use semantic colors, published profile references, and organization-visible settings only. Never infer internal organization references from a dashboard URL. ## Failure handling [#failure-handling] * `401` means the token is missing, expired, or invalid. * `403` means the authenticated user or integration lacks access to that action. * `404` means the public reference is unknown in the organization context, or the workflow is intentionally hidden from this role. * `409` means a state transition is blocked by the current workflow state. * `422` means validation failed. Read `errors` and retry only after correcting the request payload. # Authentication (/reports-api/authentication) Every Reports API operation declares its own authentication requirement in the OpenAPI contract. Follow the security declaration on the exact operation you are calling rather than assuming a section-wide rule. ## What a tenant is [#what-a-tenant-is] A tenant is the reporting account your credentials belong to. It is the Reports API equivalent of the Delivery API's organization, but the two are issued separately and their identifiers are not interchangeable. Every request carries the tenant as `X-Tenant-ID`, an opaque UUID. SpaceMedia issues it with your Reports API client credentials. There is no endpoint that discovers it and no way to derive it from a Delivery API organization reference. ## Get your first token [#get-your-first-token] Machine clients exchange approved tenant credentials at `POST /api/platform/v1/oauth/token`. The client id and secret go in an HTTP Basic header, not in the body. ```bash curl --request POST 'https://reports.spacemedia.uk/api/platform/v1/oauth/token' \ --user 'CLIENT_ID:CLIENT_SECRET' \ --header 'X-Tenant-ID: 4f1c2d6a-8e35-4a71-9b02-7c5d3e8a61f4' \ --header 'Content-Type: application/json' \ --data '{"grant_type":"client_credentials"}' ``` The response returns an opaque token, its lifetime in seconds, and the scopes actually granted. `expires_in` never exceeds 3600. ```json { "access_token": "0000000000000000000000000000000000000000", "token_type": "Bearer", "expires_in": 3600, "scope": "exports:read exports:write" } ``` Read `scope` from the response rather than assuming what you asked for was granted. Requesting a scope the tenant has not approved does not fail the exchange; it returns a token without it, and the call that needs it fails later with `403`. ## Verify the token [#verify-the-token] `GET /api/platform/v1/api/session` confirms the token, the tenant binding, and the granted scopes in one call. Use it as the first request of any integration and as a health check. ```bash curl 'https://reports.spacemedia.uk/api/platform/v1/api/session' \ --header 'Authorization: Bearer 0000000000000000000000000000000000000000' \ --header 'X-Tenant-ID: 4f1c2d6a-8e35-4a71-9b02-7c5d3e8a61f4' ``` It returns the client, the tenant, the scope array, and `expires_at`. Refresh before that timestamp rather than waiting for a `401`. ## Scopes [#scopes] | Scope | Grants | | ----------------------------------------- | ------------------------------------------------ | | `tenant:read` | Read the API session and tenant binding. | | `analytics:read` | Read published analytics. | | `calculations:read`, `calculations:write` | Read and run royalty calculations. | | `catalog:read`, `catalog:write` | Read and update catalog mapping records. | | `exports:read`, `exports:write` | List and download exports, and queue new ones. | | `imports:read`, `imports:write` | Read import state, and create or cancel imports. | | `ledger:read` | Read ledger entries. | | `payees:read`, `payees:write` | Read and update payee records. | | `statements:read` | Read royalty statements. | | `webhooks:read`, `webhooks:write` | Read and manage webhook ingress configuration. | Each endpoint page lists the scope it requires. Request the smallest set that covers your workload. ## Handling credentials [#handling-credentials] * Store client credentials and tokens only on trusted server infrastructure. * Request the smallest approved scope set. * Never reuse Delivery API credentials against the Reports API. * Revoke or rotate a client immediately when its operator or workload changes. * Treat a disabled route or tenant capability as unavailable even when the token is otherwise valid. ## Human operations [#human-operations] Routes under `/platform/v1/*` use an authenticated human session. Mutations can additionally require CSRF protection, recent multi-factor authentication, maker-checker separation, or idempotency controls. These are not machine API substitutes. Where an approval needs a person, the contract keeps it on the human surface deliberately, and there is no scope that moves it. ## Tenant isolation [#tenant-isolation] Every token, session, import, export, and evidence record is tenant scoped. Never pass a tenant reference from one authenticated context into another, and never persist cross-tenant lookup results in a shared cache. ## Common questions [#common-questions] **Which surface should my integration use?** Machine OAuth for anything automated. If the operation you need only exists on the human surface, that is a policy decision about who may approve it. **Where do I get my `X-Tenant-ID`?** SpaceMedia issues it with your Reports API client credentials. It is not the same value as a Delivery API organization reference, and no endpoint returns it. **Can I reuse my Delivery API token here?** No. The two APIs issue separate credentials against separate hosts. A Delivery API bearer token is rejected by `reports.spacemedia.uk`. **My token is valid but the call is denied. Why?** A valid token does not imply an enabled route or an approved tenant capability. See [Availability](/reports-api/availability). **How often should I rotate a client?** On any change of operator or workload, and immediately on suspected exposure. Rotation is cheap; an unrotated credential after a team change is not. **What must never go in a support ticket?** Credentials, bearer tokens, signing secrets, report files, and customer financial data. Send the operation, UTC timestamp, environment, sanitized request and response, public reference, and correlation identifier instead. # Availability (/reports-api/availability) Reports API routes are guarded capabilities. The OpenAPI contract documents implemented behavior, but route publication, tenant access, scopes, and production approval are four separate controls on top of it. This is why "the endpoint is in the spec" and "I can call the endpoint" are different statements. ## Availability checklist [#availability-checklist] Confirm all five before depending on an operation in production. 1. The route family is enabled in the target environment. 2. The tenant is approved for that capability. 3. The client or human role has the documented authority. 4. Required scopes, CSRF, MFA, and idempotency controls are satisfied. 5. The production release is listed in the [Reports API changelog](/changelog/reports-api). ## Compatibility policy [#compatibility-policy] | Change type | What to expect | | -------------------- | ------------------------------------------------------------------------------------------------------------------------ | | Compatible addition | New optional fields, enum values, or operations can appear at any time. Clients must tolerate unknown fields and values. | | Breaking replacement | Announced with a migration path and sunset information. | | Deprecation | Minimum 180 days for stable operations. | The contract uses semantic contract versions. Pin your expectations to the contract version, not to a snapshot of the response shape you happened to observe. ## Support evidence [#support-evidence] When reporting an integration problem, provide the operation, UTC timestamp, environment, sanitized request and response, public resource reference, and correlation identifier when available. Never include credentials, bearer tokens, signing secrets, report files, or customer financial data. ## Common questions [#common-questions] **I get a denial on an operation I used last week. Is this an outage?** Check tenant policy and route flags first. A capability denial is a configuration state and looks nothing like an outage in cause or remedy, even if it looks similar in your logs. **Should my client retry a capability denial?** No. Retrying does not change a policy decision. Surface it to an operator instead. **How do I know a new operation is safe to adopt?** When it appears in the [changelog](/changelog/reports-api) as a production release and your tenant is approved for it. # Reports API (/reports-api) The Reports API is the money side of SpaceMedia: royalty report intake, normalized analytics, exports, catalog mapping review, reconciliation, anomalies, disputes, and payout exceptions. It is a separate product from the [Delivery API](/delivery-api), with its own host, its own credentials, its own release notes, and its own availability controls. Credentials are never interchangeable between the two. ## Before you integrate [#before-you-integrate] 1. Confirm the route family you need is enabled in the target environment. 2. Confirm your tenant is approved for that capability. 3. Use machine OAuth only for operations that explicitly support it. 4. Check the [Reports API changelog](/changelog/reports-api) before upgrading a client. Full detail is in [Availability](/reports-api/availability). ## Four rules for financial data [#four-rules-for-financial-data] 1. **Never parse an amount into a float.** Keep decimal amounts as strings or arbitrary-precision decimals. Rounding errors in royalty data are expensive to unwind. 2. **Keep currency and period attached.** An amount without its currency and reporting period is not a number you can reconcile. 3. **Treat a capability denial as unavailable, not broken.** A feature-flag or tenant-policy denial is a configuration state, not a transient failure worth retrying. 4. **Tolerate unknown fields and values.** Compatible additions can introduce new optional fields, enum values, and operations at any time.
A documented operation is not a granted one

The contract describes implemented behavior. Route publication, tenant approval, client scopes, and production sign-off are separate controls. Confirm all of them before depending on an operation in production.

## Environment [#environment] The Reports API runs at `https://reports.spacemedia.uk`. Guarded routes stay unavailable until their deployment flag and tenant policy are enabled. # How Reporting Works (/reports-api/introduction) The Reports API covers the operational lifecycle around royalty reporting: report intake, published analytics, exports, mapping and catalog review, reconciliation, anomalies, disputes, payout exceptions, and signed webhook ingress. It runs on its own host, `reports.spacemedia.uk`, with its own credentials. Nothing carries over from the Delivery API. ## Tenants [#tenants] Everything here is scoped to a **tenant**: the reporting account your credentials belong to. Where the Delivery API says organization, the Reports API says tenant. They are the same idea, but issued separately, and one identifier never stands in for the other. You send the tenant on every request as `X-Tenant-ID`. SpaceMedia gives you the value along with your client credentials. Because every token, import, export, and evidence record is bound to one tenant, a reference from one tenant is meaningless in another, and cross-tenant results must never share a cache. ## The two access surfaces [#the-two-access-surfaces] This is the most important thing to understand before you write any code. | Surface | Intended use | Authentication | | -------------------- | ----------------------------------- | --------------------------------------------------------------------------- | | `/api/platform/v1/*` | Tenant-scoped machine integrations | OAuth bearer token with operation-specific scopes | | `/platform/v1/*` | Authenticated operational workflows | Human session, CSRF protection, and step-up authentication where documented | They are not interchangeable. Human review and approval operations stay outside machine authority on purpose, and no amount of scope on a machine client grants them. If an operation you need is only on the human surface, that is a deliberate control, not a gap to work around. ## Integration principles [#integration-principles] **Preserve decimal precision.** Keep amounts as strings or arbitrary-precision decimals. A float somewhere in your pipeline is a reconciliation failure waiting to be discovered months later. **Keep context attached to every value.** Currency and reporting period travel with the amount. Storing a bare number loses the only things that make it comparable. **Use references exactly as returned.** Public references are opaque. Do not parse, shorten, or regenerate them. **Do not infer authorization from a visible control.** A dashboard button is not evidence that your machine client can perform the same action. **Reconcile against evidence resources.** Completed imports and exports have documented evidence records. Use them rather than assuming success from a `200`. **Treat flag and policy denials as unavailable capability.** They are configuration states, not transient server failures, and retrying will not change the outcome. ## Common questions [#common-questions] **Can I use my Delivery API credentials here?** No. The two APIs have separate credentials, hosts, scopes, and release cycles. Never reuse one against the other. **Why can I read an operation in the contract but not call it?** The contract documents implemented behavior. Route publication and tenant approval are separate controls. See [Availability](/reports-api/availability). **How should I handle a response field I do not recognize?** Ignore it safely. Compatible additions can introduce new optional fields and enum values at any time, and a strict parser will break on the next release. **Where are the exact request and response shapes?** On each endpoint page, generated from the checked-in OpenAPI 3.1 contract. Start at [machine authentication](/reports-api/endpoints/oauth/exchangePlatformClientCredential) and select operations from the sidebar. # Email Theme Customizer (/addons/email-theme-customizer) Every platform sends email: verification, password resets, notifications, account updates. Email Theme Customizer makes those look like they came from you rather than from generic defaults. Find it at **Settings > Email Theme** once the add-on is active.
This is design, not delivery

Who the email comes from is set in Email Setup . This add-on controls what it looks like once it arrives. Configure the sender first, otherwise you are branding emails that still come from a fallback address.

## What you can change [#what-you-can-change] | Control | Affects | | ----------------------------- | --------------------------------------------------------- | | **Logo URL** | The image at the top of every email | | **Brand name** | The name shown in the email header | | **Primary and accent colors** | Headings and call-to-action buttons | | **Button text and radius** | How action buttons read and look | | **Muted text** | Secondary and fine print | | **Font** | The typeface, with an email-safe fallback | | **Email width** | How wide the content column renders | | **Footer note** | An optional line at the bottom, such as a company address | | **Theme preset** | A complete starting point you can adjust | ## Publishing [#publishing] You edit a draft, preview it against real templates, and publish one approved design. Until you publish, your platform keeps sending the SpaceMedia defaults, so there is no in-between state that reaches customers half-finished. If the license is not active yet, you can still edit and preview. Publishing unlocks once it is. ## Getting it right [#getting-it-right] Email rendering is far less forgiving than the web. A few things that consistently matter: * **Use a hosted logo URL that is publicly reachable.** Anything behind a login shows as a broken image. * **Keep the logo modest.** Many clients scale images unpredictably, and a huge header pushes your actual message below the fold. * **Check contrast on the button.** Button text over your brand color is the single most common readability failure. * **Assume images are blocked.** A meaningful proportion of recipients see text only, so the email must still make sense without the logo. * **Preview on a phone.** Most platform email is opened on mobile. Send yourself a real password reset before you publish. The preview is accurate, but a real message in a real inbox catches things the preview cannot. ## If you deactivate it [#if-you-deactivate-it] Editing stops and the sidebar entry disappears. If nothing has been published, the SpaceMedia default design stays in place, which means emails always send correctly regardless of what happens to the theme. ## Common questions [#common-questions] **Can I edit the wording of the emails?** No. This controls the visual design. The content of platform emails is standard. **Does this affect emails I send from my own systems?** No, only emails the platform sends. **Will this improve deliverability?** No. Deliverability comes from domain authentication in [Email Setup](/branding/email). **Can I publish more than one design?** One published design applies to your whole platform. # Enterprise Delivery API (/addons/enterprise-delivery-api) The Enterprise Delivery API add-on unlocks programmatic access to your platform. It is for teams doing volume: syncing catalog into their own systems, automating repetitive delivery work, feeding a BI dashboard, or connecting a partner portal. Once active, credentials are created at **Settings > DDEX Gateway**. ## Do you need it? [#do-you-need-it] You probably do if you are: * Moving more releases per week than a person wants to click through * Keeping catalog or delivery status in sync with a system you already run * Feeding sales and analytics into finance or BI tooling * Building a partner-facing portal on top of your platform You probably do not if the dashboard covers your workflow today. Nothing is lost by waiting until volume justifies it. ## Creating credentials [#creating-credentials] Open **Settings > DDEX Gateway**. The API access panel shows whether credentials exist, the token exchange path, the token lifetime, and which capabilities are enabled. Select **Create API credentials**. Creating and rotating is always an explicit action, never automatic. Copy the API key and the API secret immediately. The secret is shown once and cannot be retrieved afterwards. Store both in your secret manager. Never in a browser, a spreadsheet, a shared document, or a chat message. Confirm the capabilities match what the integration actually does, then hand your developer the [Quickstart](/delivery-api/api-quickstart). ## How access works [#how-access-works] Your integration exchanges the key and secret for a bearer token, then sends that token on every request. Tokens always expire. The default lifetime is one hour, and you can configure anywhere from 5 minutes to 24 hours. New credentials start with read-only catalog access. Everything beyond that is granted deliberately. | Area | What it covers | | -------------- | ----------------------------------------------------------------- | | Catalog | Artists, releases, tracks, splits, smartlinks, and reference data | | Account | Account settings and labels | | Billing | Subscriptions, orders, packages, and upgrades | | Branding | Theme and email theme configuration | | Users | Your customer accounts | | Members | Staff, roles, and permissions | | Release review | The review and processing queue | | Copyright | Copyright records and wallet | | DDEX | DDEX read, write, and manage | | Webhooks | Webhook configuration | Full endpoint detail is in the [Delivery API reference](/delivery-api). Reporting data has its own [Reports API](/reports-api). ## Add-ons that gate API areas [#add-ons-that-gate-api-areas] Some groups need their product add-on active as well. Member endpoints, for example, require both this add-on and [Team Members](/addons/members-management). Without both, those calls return an add-on access error even though the credential itself is valid. ## Running it safely [#running-it-safely] **One credential per system.** Sharing one credential between your BI tool and your partner portal means you cannot revoke one without breaking the other, and you cannot tell them apart in the audit trail. **Grant the narrowest capability set.** A reporting sync does not need write access to your catalog. **Rotate on people changes.** When whoever set up an integration leaves, rotate. Rotation revokes every existing bearer token immediately, so schedule it rather than doing it mid-day. **Use it for repeatable work.** One-off manual changes belong in the dashboard, where they are attributable to a person.
The secret is shown once

If it is lost, the only recovery is rotating the credentials, which immediately invalidates every token issued from the old pair. Capture it into your secret manager at the moment you create it.

## Common questions [#common-questions] **Is this a subscription?** It is licensed as a one-time purchase for your workspace. Check the Addons page for the terms that apply to you. **Can I test without touching live data?** Yes. See [Staging Environment](/delivery-api/staging-environment). **Do API permissions follow my staff roles?** API clients carry their own capabilities. Where an integration acts on behalf of one of your customers, that supplies ownership context, not extra authority. See [Acting for Users](/delivery-api/acting-for-users). **What does a 403 mean?** A permission or capability failure, not a missing endpoint. Check the credential's capabilities first, then whether a gating add-on is active. See [Troubleshooting](/delivery-api/troubleshooting). ## Next [#next] # Knowledge Base Manager (/addons/knowledge-base-manager) Knowledge Base Manager gives your customers somewhere to find answers without contacting you. Done well, it removes the most common third of your support volume. Once the add-on is active, installing it offers to open the FAQ area directly, and you can return to it from the help navigation in your dashboard. ## What to write first [#what-to-write-first] Do not start with a content plan. Start with your last fifty support requests and count the repeats. The top ten answers are your first ten articles. Typical high-value topics for a distribution platform: | Topic | Why it repeats | | ------------------------------------- | ---------------------------------------------------------------- | | What happens after I submit a release | Customers cannot see the review queue and assume something broke | | Why a release was rejected | The same handful of metadata and artwork issues, over and over | | Audio and artwork requirements | Asked before every first release | | How long distribution takes | Impossible to guess, so everyone asks | | How revenue splits work | The most misunderstood feature on any distribution platform | | When and how payouts arrive | Money questions always generate tickets | | What my membership includes | Especially at the point of upgrading | ## Writing articles that work [#writing-articles-that-work] * **Title it as the question the customer asks**, not the feature name. "Why was my release rejected?" beats "Release QC". * **Answer in the first two sentences.** Anyone still reading paragraph four has already given up and opened a ticket. * **End with the next action.** What should they do now. * **One question per article.** Bundled articles are unfindable by search. * **Group by intent, not by your org chart.** Customers do not know which of your teams owns what. ## Keeping it alive [#keeping-it-alive] A stale help center is worse than none, because it teaches customers not to trust it. 1. Give one person ownership of content quality. 2. Review monthly against your [ticket](/addons/support-desk-manager) volume and add whatever is repeating. 3. Update articles when you change pricing, policy, or a workflow. This is easy to forget on the day of the change. 4. Delete anything that no longer reflects the product. ## Connect it up [#connect-it-up] Point the **Help center URL** in [Support Settings](/branding/support) at your knowledge base so it appears where customers look for help. When you answer a ticket with something already written up, link to the article. It reinforces that the help center is worth checking first. ## Common questions [#common-questions] **Can customers search it?** Yes. That is what makes titling articles as real questions matter so much. **Should I duplicate SpaceMedia's documentation here?** No. Write about your platform: your pricing, your review standards, your turnaround times, your support process. Those are the things only you can answer. **What happens if I deactivate the add-on?** The area leaves the sidebar and content is no longer editable. Your articles are retained, so reactivating restores them. **How many articles do I need to start?** Ten good ones covering your actual repeat questions beat fifty thin ones. # Team Members (/addons/members-management) Team Members adds staff accounts to your dashboard. Without it, your platform has one operator. With it, you can give each person exactly the areas they need and nothing else. Find it at **Settings > Members** once the add-on is active.
Members are not Users

Members are your internal staff. Users , under Overview in the sidebar, are your customers: the artists and labels who registered on your portal. They are separate directories with separate permission models.

## Role presets [#role-presets] Start from a preset. They are built around real jobs, and you can narrow one further with a custom role if you need to. | Preset | Can do | Typical hire | | ---------------------- | ------------------------------------------------------------------- | -------------------------- | | **Org Admin** | Everything except deleting members and roles | Your second in command | | **Distributor** | Artists, releases, tracks, release processing, QC scoring, tickets | Delivery operations | | **Label Manager** | Artists, releases, tracks, tickets, and user lookup | Label relationship manager | | **Content Manager** | Artists, releases, tracks, tickets | Catalog and metadata work | | **Accounting Manager** | Payouts, revenue splits, subscriptions, membership packages, logs | Finance | | **Support Manager** | Tickets end to end, plus read access to users, releases, and tracks | Customer support | | **QC Manager** | Release review, release processing, and QC scores | Quality control | | **Read-only Analyst** | View access across catalog, finance, support, and logs. No writes | Reporting and audit | Owner and Admin are the built-in full-access roles. They are not offered as presets because you should not be handing out full access casually. ## Permission groups [#permission-groups] Custom roles are built from these groups, so you can see at a glance what any role touches. | Group | Covers | | --------- | --------------------------------------------------------------------------------- | | Dashboard | Access to the dashboard itself | | Members | Viewing, inviting, updating, suspending, and deleting staff, plus role management | | Users | Your customer accounts | | Catalog | Artists, releases, tracks, and release processing | | Finance | Payouts, revenue splits, subscriptions, and membership packages | | Support | Tickets, including priority, status, escalation, and cancellation | | Quality | QC scores | | Add-ons | Add-on management, smartlinks, and theme publishing | | Audit | Activity logs | ## Inviting someone [#inviting-someone] 1. Open **Settings > Members** and select the invite action. 2. Enter their email. 3. Pick the preset that matches their job, or select an existing custom role. 4. Review the permission list shown before you send. It is the fastest way to catch an over-broad choice. 5. Send the invitation. They set their own password when they accept. Start narrow. Widening a role later is a two-minute change; discovering someone had payout access for six months is not. ## Custom roles [#custom-roles] Use a preset unless one genuinely does not fit. When you do need a custom role: 1. Start from the closest preset rather than an empty list. 2. Remove what they do not need instead of adding one permission at a time. 3. Name it after the job, not the person. Roles marked protected cannot be edited, which keeps the presets intact as a reference point. ## Guardrails [#guardrails] The system prevents the mistakes that lock you out of your own platform: * The last owner or admin-capable member cannot be removed. * You cannot demote yourself if you are the last admin-capable account. * Roles are always scoped to your own organization. * A duplicate active invitation is blocked until the existing one is cancelled or accepted. ## Audit [#audit] Every invitation, role change, suspension, removal, and permission update is recorded. Check it after any access change, and during any offboarding. ## Using the Members API [#using-the-members-api] Member endpoints require **both** Team Members and the [Enterprise Delivery API](/addons/enterprise-delivery-api) add-on to be active. If only one is active, those endpoints return an add-on access error even with a valid credential. In API requests, use the documented `preset` values and the permission keys returned by the member permissions endpoint. The names in the table above are display labels. ## Common questions [#common-questions] **Does a member count as one of my customers?** No. Staff accounts and customer accounts are separate. **Can a member see other organizations?** No. Roles are scoped to your organization only. **What happens if I deactivate the add-on?** The Members area leaves the sidebar. Existing staff accounts and roles are retained, so reactivating restores them. **Someone left the company. What do I do?** Suspend or remove them in Members, then check the audit trail for anything they changed recently. If they held API credentials, rotate those too. # Add-ons (/addons/overview) Add-ons are optional capabilities you switch on per platform. Some are included, some are a one-time purchase, and some are a monthly subscription with a trial. The dashboard shows what applies to your workspace. **Settings > Addons** is the store. Installed add-ons appear as their own sidebar entries. ## The catalog [#the-catalog] | Add-on | What it gives you | | ---------------------------------------------------------- | ---------------------------------------------------- | | [Team Members](/addons/members-management) | Staff accounts, role presets, and permission control | | [Smartlinks](/addons/release-smartlinks) | Branded release landing pages with click analytics | | [Theme Editor](/addons/theme-editor) | Dashboard colors, fonts, spacing, and layout | | [Email Theme Customizer](/addons/email-theme-customizer) | Branded design for outbound platform emails | | [Support Desk Manager](/addons/support-desk-manager) | In-portal ticketing with owners and statuses | | [Knowledge Base Manager](/addons/knowledge-base-manager) | A searchable help center for your customers | | [Enterprise Delivery API](/addons/enterprise-delivery-api) | API credentials for connecting your own systems |
Pricing is shown in the dashboard

Availability, price, currency, and trial length are configured per workspace and can differ from one platform to another. Always check the Addons page in your own dashboard for the terms that apply to you rather than assuming a figure from elsewhere.

## Billing models [#billing-models] | Model | How it works | | ------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Free** | Install and activate immediately. No checkout. | | **One-time** | Pay once through secure checkout, then activate. Access does not expire. | | **Monthly** | A subscription billed on a cycle. Access continues while the license is active. | | **Trial** | Starts with card authorization. The first charge date is shown before you confirm, and it converts automatically unless you cancel before the trial ends. | ## The lifecycle [#the-lifecycle] **Browse.** Open **Settings > Addons** and compare what is available. Each entry has a detail page with its features, screenshots, and documentation link. **Install.** Free add-ons activate straight away. Paid ones open secure checkout first, with a summary of exactly what you are agreeing to. **Activate.** Active add-ons expose their sidebar entry, their pages, and their capabilities. Most add-ons offer to take you straight to the page they just unlocked. **Deactivate.** The sidebar entry disappears and direct page access is blocked. Your data stays where it is. ## Deactivating safely [#deactivating-safely] Deactivation is not deletion. Smartlinks stop being editable, the Theme Editor leaves the sidebar, the ticket area closes, but the underlying records remain, and reactivating restores access. Two things to know before you deactivate something customer-facing: * If a published dashboard or email theme is in place, deactivating the editor removes your ability to change it, not the published result. * Deactivating an add-on that gates an API area causes those API calls to start failing, even though the credential itself is still valid. ## Add-ons that gate the API [#add-ons-that-gate-the-api] Some Delivery API endpoint groups require both the [Enterprise Delivery API](/addons/enterprise-delivery-api) add-on and the add-on for that feature. The clearest example is member management: without [Team Members](/addons/members-management) active, member endpoints return an add-on access error even with a perfectly valid credential. This is deliberate. Buying API access does not silently expose product areas you never bought. ## Common questions [#common-questions] **Can I try a paid add-on before committing?** Where a trial is offered, yes. Trials require card authorization, and the first charge date is shown before you confirm. **What happens when a trial ends?** It converts to the paid plan automatically unless you cancel first. If a subscription lapses, the dashboard prompts you to choose a plan to restore the feature. **Who can install add-ons?** Platform admins with add-on management permission. See [Team Members](/addons/members-management) for how to grant it. **A page says the add-on is not installed. Why?** Either it was never installed, or it was deactivated. Direct page access is blocked in both cases. # Smartlinks (/addons/release-smartlinks) Smartlinks give every release one shareable page instead of a dozen platform links. Listeners land on your branded page and pick their service. You get the click data. Find it at **Operations > Smartlinks** once the add-on is active. ## What you control [#what-you-control] | Capability | Detail | | -------------------- | ------------------------------------------------------------------------------- | | **Branded pages** | One page per release, with artwork, title, and creators pulled from the catalog | | **Store routing** | Spotify, Apple Music, Deezer, YouTube Music, and other configured destinations | | **Platform rules** | Force a link to appear, block one entirely, or set the order, at platform level | | **Customer control** | Artists choose which links show, within the set you allow | | **Analytics** | Views and clicks, total and last 30 days, per link | ## Link visibility [#link-visibility] Every link on a page resolves to one of these, and the platform rule always wins. | State | Meaning | | ---------------------- | ------------------------------------------------ | | **Forced by org** | You require this link. The artist cannot hide it | | **Blocked by org** | You have removed this destination for everyone | | **Hidden by end user** | Allowed by you, hidden by the artist | | **Visible** | Allowed and shown | Set your platform rules before you invite customers to edit their links. Changing the rules afterwards silently changes pages that are already being promoted. ## Who can publish a smartlink [#who-can-publish-a-smartlink] Access is decided per release. | Mode | Behavior | | --------------------- | ---------------------------------------------------------------------- | | **Free** | Anyone eligible can publish, with no extra charge | | **Membership or PPR** | Access comes with the customer's membership or pay-per-release package | | **Base fee** | A per-release fee applies when no package grants access | | **Blocked** | Not available until your rules grant it | Decide this before launch. Moving a release from free to paid after artists have started using smartlinks is a conversation you would rather not have. ## Status [#status] Smartlinks are **Draft**, **Live**, or **Disabled**. Draft pages are not public. Disabling a live page takes it down without deleting its history or analytics. ## Reading the analytics [#reading-the-analytics] Views tell you how much traffic arrived. **Clicks are what matter**, because they tell you where listeners actually went. For a campaign, look at these together: * **Clicks per platform**, to see where your audience really is * **Referrers**, to see which channel delivered the traffic * **UTM campaign values**, to compare your own campaigns * **Device mix**, because a mobile-heavy audience changes how the page should be ordered Tag every campaign link with UTM parameters. Without them, all your traffic collapses into one undifferentiated bucket and the analytics stop being useful. ## Practical setup [#practical-setup] 1. Decide the access mode: included for everyone, tied to packages, or charged per release. 2. Configure your platform-level allowed, blocked, and ordered destinations. 3. Put the two or three services your audience actually uses at the top. 4. Publish one release as a test and click every link yourself. 5. After each campaign, prune destinations that get no clicks. A shorter page converts better. ## Common questions [#common-questions] **Do smartlinks work on my custom domain?** Pages are served on your branded platform. Finish [Domain Setup](/branding/domain) before promoting them. **Can I edit a smartlink after it is live?** Yes. Link visibility and ordering can change at any time, and the URL stays the same. **What happens to analytics if I disable a page?** History is kept. Re-enabling brings the page back with its data intact. **Can artists add their own destinations?** Only within the set your platform rules allow. # Support Desk Manager (/addons/support-desk-manager) Support Desk Manager replaces the shared support inbox with a proper ticket area inside your portal. Every request arrives attached to the account that raised it, which means no more asking customers which release they mean. Find it at **Operations > Tickets**, with reporting under **Operations > Ticket Dashboard**, once the add-on is active. ## Why it beats an inbox [#why-it-beats-an-inbox] | Shared inbox | Ticket area | | -------------------------------------------------- | ----------------------------------------------- | | No owner, so everyone assumes someone else replied | Every ticket has an owner | | Context lives in the customer's memory | The account, releases, and history are attached | | Status is whatever the last reply implied | Explicit status on every ticket | | Nothing is measurable | Volume, response, and resolution reporting | ## What your team can do [#what-your-team-can-do] | Action | Permission it needs | | ---------------- | ------------------------- | | See tickets | `view tickets` | | Reply and update | `update tickets` | | Change priority | `change priority tickets` | | Change status | `change status tickets` | | Escalate | `escalate tickets` | | Cancel | `cancel tickets` | The **Support Manager** preset in [Team Members](/addons/members-management) grants exactly this set, plus read access to users, releases, and tracks so agents can actually investigate. ## Setting up a workflow that holds [#setting-up-a-workflow-that-holds] **Decide who owns first response.** One named person or a rota, not "the team". **Agree a response window** and make it match what you published in [Support Settings](/branding/support). **Keep the status list short.** Three or four statuses everyone understands beats twelve nobody maintains. **Define what escalation means** and who receives it. An escalation path nobody owns is just a slower queue. **Review unresolved tickets weekly.** Backlog grows quietly and is much cheaper to catch at ten than at two hundred. ## Use the history [#use-the-history] Before asking a customer to repeat themselves, read the ticket history and their account. A large share of support time goes on re-establishing context that was already captured. ## Turn repeats into content [#turn-repeats-into-content] When the same question arrives for the third time, it is not a support problem, it is a documentation gap. Write it up in [Knowledge Base Manager](/addons/knowledge-base-manager) and link to it from your reply. The two add-ons are designed to work together. ## Reading the Ticket Dashboard [#reading-the-ticket-dashboard] Look at three things: * **Volume over time.** A spike usually follows a release, a price change, or a broken flow. * **Time to first response.** The number your customers actually feel. * **Resolution rate.** If it drops while volume is flat, tickets are stalling rather than arriving faster. ## Common questions [#common-questions] **Do customers need a separate account?** No. They raise tickets from inside your portal with their existing account. **Can I still take email support?** Yes. Keep [Support Settings](/branding/support) filled in. Many platforms publish both and steer customers to tickets for anything account-specific. **What happens to tickets if I deactivate the add-on?** The area closes and the sidebar entry disappears. Ticket data is retained, so reactivating restores it. **Should I use this or Zendesk?** If you already run Zendesk, connect it with [JWT SSO](/branding/jwt-sso) instead. Running both splits your team's attention. # Theme Editor (/addons/theme-editor) Theme Editor changes how the dashboard looks for everyone on your platform. You work on a draft, preview it, and publish only when it is ready. Find it at **Settings > Theme Editor** once the add-on is active. ## What you can change [#what-you-can-change] | Control | Affects | | ----------------------------- | ------------------------------------------------ | | **Theme preset** | A complete starting point you can then adjust | | **Primary and accent colors** | Buttons, links, highlights, and active states | | **Surface tone** | The background and card tones behind the content | | **Font** | The typeface used across the dashboard | | **Body and heading size** | The type scale, from XS to XL | | **Button radius** | How rounded controls appear | | **Sidebar mode** | Expanded or compact | | **Content layout** | Full width or centered | | **Color mode** | How the theme resolves in light and dark | ## Draft and publish [#draft-and-publish] Nothing you change is visible to anyone else until you publish. 1. Start from a preset rather than the blank defaults. 2. Change one area at a time and save the draft as you go. 3. Preview the pages people actually use: Dashboard, Releases, Release Queue, Settings. 4. Check both light and dark mode before publishing. 5. Publish when the team agrees. **Reset to Default** returns you to the SpaceMedia defaults if a draft goes wrong. ## Preview mode [#preview-mode] Before the add-on is fully activated, the editor runs in preview mode. You can change everything and save drafts, but publishing is locked and your customers keep seeing the current published theme. A notice in the dashboard tells you this is happening, so a draft is never live by accident. ## Contrast is not optional [#contrast-is-not-optional] The most common mistake is picking a brand color that looks right on a marketing site and fails as an interface color. * Check text on buttons, not just the buttons themselves. * Check focus outlines, which people navigating by keyboard depend on. * Check error and success states, which need to stay distinguishable from your brand color. * Check both light and dark mode. A color that works in one often fails in the other. If you cannot read it comfortably at arm's length, neither can your customers. ## If you deactivate it [#if-you-deactivate-it] The Theme Editor leaves the sidebar and editing stops. A theme you already published stays published. Reactivating brings the editor back with your work intact. ## Common questions [#common-questions] **Does this change my logo or brand name?** No. Those are in [General Settings](/branding/branding). **Does this change what my customers' emails look like?** No. Emails are styled by the [Email Theme Customizer](/addons/email-theme-customizer). **Can I roll back a published theme?** Adjust the draft and publish again, or use Reset to Default and publish that. Keep a note of your color values before a large change. **Who can publish?** Publishing requires the theme publishing permission. See [Team Members](/addons/members-management). # General Settings (/branding/branding) **Settings > Brand Settings > General Settings** is the identity layer of your platform: what it is called, what it looks like in headers and browser titles, and which optional behaviors are switched on. This section stays editable during the trial, so it is the natural place to start. ## Fields [#fields] | Field | Notes | | ---------------------- | ------------------------------------------------------------------------------------------------------- | | **Brand name** | Required. Shown in headers, browser titles, workspace views, and client listings. Up to 255 characters. | | **Logo** | JPG, PNG, GIF, or WEBP, up to 16 MB. Leave it alone to keep the current logo. | | **Currency** | Your default commercial currency for billing, pricing, and financial displays. | | **Default label name** | The fallback label applied when a release or template does not set its own. Up to 150 characters. | | **Social links** | Public Instagram, X, YouTube, and Facebook URLs shown for your brand. Full URLs only. | ## Toggles [#toggles] | Toggle | Turn it on when | | ----------------- | -------------------------------------------------------------------------------------------------------------------------------- | | **Custom labels** | Your customers should be able to enter their own label name while creating a release. It does not unlock label management tools. | | **Captcha** | You want CAPTCHA protection on registration to reduce bot signups. | | **Upgrade CTA** | You want upgrade prompts shown where plan expansion is relevant. | | **Prepay** | You want prepaid purchase flows available where supported. | Turn a toggle on only when the workflow behind it is ready. Enabling Upgrade CTA before you have published a membership plan, for example, points customers at an empty page. ## Setting it up [#setting-it-up] Open **Settings > Brand Settings** and stay on **General Settings**. Enter your brand name, then upload your logo and wait for the preview to finish processing. Choose your currency and default label name. Switch on only the toggles you are ready to support, then add your social URLs. Save, then open your portal in a private browser window to confirm the header, browser title, and login screen look right. ## Before you change the logo [#before-you-change-the-logo] Write down the current values first. If a change does not work out, restoring is much faster when you have the previous logo file and settings to hand. Check the result on a phone as well as a desktop. Wide logos that look fine in the header often break the mobile layout. ## Common questions [#common-questions] **Where are the dashboard colors and fonts?** In the [Theme Editor](/addons/theme-editor), not here. General Settings covers brand identity; Theme Editor covers the visual system. **Can I inject custom JavaScript or tracking code?** No. Custom JavaScript is not supported in brand settings. **Why did my logo upload fail?** The file type or the size. It must be JPG, PNG, GIF, or WEBP and 16 MB or smaller. Re-uploading the same file will not fix a validation error. **Does changing branding affect my API credentials?** No. Credentials and their capabilities are unaffected by anything on this page. ## Next [#next] [Languages](/branding/languages) is the other section you can configure during the trial. # Domain Setup (/branding/domain) **Settings > Brand Settings > Domain Setup** puts your portal on your own domain, so customers log in at `app.yourlabel.com` instead of a SpaceMedia address. Your default workspace domain keeps working throughout. Nothing goes offline while you set this up, and the switch only happens once the new domain is fully ready. ## What you need first [#what-you-need-first] * Access to DNS for the domain you want to use. * The root domain, not a URL. Enter `yourlabel.com`, not `https://yourlabel.com`, and not `www.yourlabel.com`. * Ideally, a lowered TTL on the records you are about to change, set a day in advance. ## The three steps [#the-three-steps] The page walks you through these in order and will not let you skip ahead. **Create the ownership record.** Enter your domain and save. The page generates a TXT record with a host name and an exact value. **Verify domain ownership.** Publish that TXT record at your DNS provider exactly as shown, wait for propagation, then select **Verify ownership**. Verification only succeeds when the exact value is visible in live DNS. **Connect the verified domain.** Publish the CNAME record shown in step 3. The page checks DNS automatically and refreshes on its own. Once the record is live and the certificate is ready, your portal switches to the new domain. The certificate is issued for you. There is nothing to buy or upload. ## Reading the status banner [#reading-the-status-banner] | Status | What it means | What to do | | ---------------------------------- | -------------------------------------------- | --------------------------------------------------------------------- | | Custom domain not set up | No domain saved yet | Enter your domain and save | | Verify domain ownership | TXT record generated, not yet proven | Publish the TXT record, then select Verify ownership | | Domain ownership challenge expired | The proof window closed | Save the domain again to generate a fresh TXT record | | Domain ownership verified | Proof accepted, preparing the switch | Publish the CNAME and wait | | Custom domain saved, DNS pending | Waiting to see the CNAME in live DNS | Confirm the record is published and wait | | DNS mismatch detected | DNS resolves, but not to the required target | Replace the live value with the exact target shown | | Custom domain update in progress | Changes are being applied | Wait. Propagation can take 24 to 48 hours depending on your registrar | | Custom domain configured | Done | Test login and navigation on the new domain | | Custom domain update failed | The last attempt did not complete | Re-check the DNS instructions and try again | ## If verification will not pass [#if-verification-will-not-pass] Work through these in order. 1. **Compare the value character for character.** A trailing space or a partially copied token is the most common cause. 2. **Check the host name.** Some DNS providers append the domain automatically, which turns the correct host into a doubled one. 3. **Look for a conflicting record.** An existing A, AAAA, or CNAME record on the same name will win over the one you just added. 4. **Wait longer before retrying.** Repeatedly re-saving the domain generates a new challenge and restarts the clock. Changing the hostname mid-propagation restarts everything. If your DNS provider offers a proxy or "cloud" toggle, leave it off unless the dashboard explicitly says the proxy is supported. A proxied record hides the value the check is looking for.
Apex domains

If you are pointing a root domain such as yourlabel.com rather than a subdomain, your DNS provider must support CNAME flattening, ALIAS, or ANAME records, and the flattened addresses must match the required target exactly. Most modern providers support this. If yours does not, use a subdomain such as app.yourlabel.com instead.

## After the switch [#after-the-switch] * Open the domain over HTTPS in a private browser window and check login, navigation, and images. * Move on to [Email Setup](/branding/email). Sender email requires a connected custom domain, and the sender address must be on this domain. * Keep your default workspace domain in your own notes as a recovery path. ## Changing the domain later [#changing-the-domain-later] You can. Saving a different domain starts the same three steps again, and your current domain stays live until the new one is fully ready and its certificate is active. The old configuration is cleaned up only after the switch succeeds. ## Common questions [#common-questions] **Can I use a subdomain?** Yes, and it is usually the simplest option. `app.yourlabel.com` or `music.yourlabel.com` both work. **Do I need to include www?** No. Enter the root domain only. The field rejects a `www.` prefix. **Will my portal go down while DNS propagates?** No. The existing domain serves traffic until the new one is verified, connected, and certified. **Someone else is already using this domain on SpaceMedia. What now?** A domain can only be connected to one organization. Contact support if you believe it should be yours. **Why is this section greyed out?** Domain Setup is locked until the 30-day free trial is started with an authorized card. See [Getting Started](/gettingstarted). # Email Setup (/branding/email) **Settings > Brand Settings > Email Setup** makes password resets, notifications, and account emails arrive from your brand instead of a neutral platform address. ## Connect your domain first [#connect-your-domain-first] This section will not save without a connected custom domain, because the sender address has to be on it. Finish [Domain Setup](/branding/domain) first. ## The three steps [#the-three-steps] **Connect your domain.** Already done if Domain Setup shows the domain as configured. **Set the sender identity.** Enter a sender name, which is the display name recipients see, and a sender address on your connected domain. `noreply@yourlabel.com` is the suggested default. **Publish authentication DNS records.** The page generates three TXT records: a domain verification record, a DKIM record, and a DMARC record. Publish all three at your DNS provider exactly as shown, then wait. The page refreshes the status on its own. Once verification and authentication both complete, your address becomes the live sender. ## Sender address rules [#sender-address-rules] | Rule | Detail | | -------------------------------- | --------------------------------------------------------------------------------------------------------------------------- | | Must be on your connected domain | A subdomain is not treated as equivalent. If your domain is `yourlabel.com`, then `noreply@mail.yourlabel.com` is rejected. | | `whitelabel@` is reserved | That local part is reserved for platform administration. Pick another. | | Sender name is required | Up to 255 characters. This is the display name, such as your brand name. | | Reply-To must match | If you set one, it has to be on the same domain and cannot use a reserved local part. | ## Reading the status banner [#reading-the-status-banner] | Status | What it means | | --------------------------------------- | --------------------------------------------------------------------- | | Custom domain required | Finish [Domain Setup](/branding/domain) first | | Ready for sender email | Enter a sender address on your domain to generate the DNS records | | DNS verification pending | Records generated, not yet visible in live DNS. Publish them and wait | | Domain verified, authentication pending | Ownership confirmed, DKIM and DMARC still finishing | | Email sending is ready | Your address is live and authenticated |
Emails still send before authentication completes

Until your domain finishes authenticating, platform emails go out from a neutral fallback address rather than yours. Nothing breaks and no customer email is dropped, but the branding is not yours yet, so finish this before you invite real customers.

## If you receive a verification code by email [#if-you-receive-a-verification-code-by-email] You can ignore it. Some providers send a one-time sender confirmation code to the mailbox. It is not needed here. Publish the TXT records and the sender activates automatically once DNS authentication succeeds. ## If authentication will not complete [#if-authentication-will-not-complete] 1. **Confirm all three records are published.** Verification, DKIM, and DMARC are separate records and all three matter. 2. **Check for a truncated DKIM value.** DKIM values are long and some DNS interfaces split or cut them. The stored value must match exactly. 3. **Check for an existing DMARC record.** A domain can only have one DMARC record. If you already have one, reconcile rather than duplicate. 4. **Wait.** DNS propagation can take up to 24 to 48 hours depending on your registrar. ## Test before you launch [#test-before-you-launch] Send yourself a real platform email, such as a password reset, from an address outside your organization. Confirm the From name and address are yours, the message is not in spam, and any links point at your domain. ## Common questions [#common-questions] **Can I use my everyday mailbox as the sender?** You can, but a dedicated `noreply@` address is better. Replies to platform emails are rarely monitored, which is what [Support Settings](/branding/support) is for. **Can I change the sender later?** Yes. Keep it on the same connected domain and the change takes effect once saved. **Does this affect how platform emails look?** No, only who they come from. Design is handled by the [Email Theme Customizer](/addons/email-theme-customizer) add-on. **Why is this section greyed out?** Email Setup is locked until the 30-day free trial is started with an authorized card. See [Getting Started](/gettingstarted). # JWT SSO (Zendesk) (/branding/jwt-sso) **Settings > Brand Settings > JWT SSO (Zendesk)** lets a customer who is already signed in to your portal open your Zendesk help center without logging in again. This is a purpose-built Zendesk integration, separate from the general-purpose [SSO Identity](/branding/sso-identity) and [SSO Consumer](/branding/sso-consumer) sections. ## When you would use this [#when-you-would-use-this] You run support on Zendesk and you want customers to reach it from inside the portal without a second account. Everything Zendesk knows about who they are comes from the signed handoff your portal sends. If you use the in-portal [Support Desk Manager](/addons/support-desk-manager) instead, you do not need this. ## The three fields [#the-three-fields] | Field | Direction | What it is | | ----------------------- | ------------ | ---------------------------------------------------------------------------------------------- | | **Client redirect URI** | Read-only | The login URL that receives the Zendesk JWT handoff for your workspace. Copy this into Zendesk | | **Return URL** | You enter it | The Zendesk URL users land on once the handshake completes | | **JWT Secret** | You enter it | The shared signing secret used to generate the Zendesk-compatible token | ## Setting it up [#setting-it-up] 1. In Zendesk, enable JWT single sign-on and generate a shared secret. 2. Paste that secret into **JWT Secret** here. 3. Copy the **Client redirect URI** from this page into your Zendesk SSO configuration as the remote login URL. 4. Enter the **Return URL** that Zendesk should land users on. 5. Save, then test the handoff with a real customer account. Leave the JWT Secret field empty when re-saving to keep the stored secret unchanged.
The secret is the whole security model

Anyone holding this secret can mint a token that Zendesk will accept as any user. Store it in a secret manager, never paste it into a ticket or a screenshot, and rotate it in both systems at the same time if it is ever exposed.

## Testing the handoff [#testing-the-handoff] 1. Sign in to your portal as a test customer. 2. Open the help center link from inside the portal. 3. Confirm Zendesk shows the correct name and email, not a new empty profile. 4. Sign out of the portal and confirm a fresh handoff is required. ## If the handoff fails [#if-the-handoff-fails] | Symptom | Usual cause | | --------------------------------------- | --------------------------------------------------------------------------------- | | Zendesk rejects the token | The secret differs between the two systems, or was rotated in only one | | The user arrives as a new blank profile | Zendesk is matching on a field the handoff does not provide | | Users land on the wrong page | The Return URL points somewhere other than the intended help center entry point | | Nothing happens | The remote login URL in Zendesk does not match the Client redirect URI shown here | ## Common questions [#common-questions] **Does this work with help desks other than Zendesk?** This section is built for Zendesk's JWT SSO scheme. For a general OAuth 2 integration, use [SSO Identity Settings](/branding/sso-identity). **Does this replace my support email?** No. Keep [Support Settings](/branding/support) filled in either way. **Why is this section greyed out?** SSO sections are locked until the 30-day free trial is started with an authorized card. See [Getting Started](/gettingstarted). # Languages (/branding/languages) **Settings > Brand Settings > Languages** controls which languages your customers can switch the portal into, and which one they see before they choose. Every enabled language is included in the platform at no extra cost. ## Supported languages [#supported-languages] | Language | Code | Direction | | -------------------- | ------- | ------------- | | English | `en` | Left to right | | Spanish | `es` | Left to right | | Portuguese (Brazil) | `pt-BR` | Left to right | | French | `fr` | Left to right | | German | `de` | Left to right | | Italian | `it` | Left to right | | Dutch | `nl` | Left to right | | Polish | `pl` | Left to right | | Arabic | `ar` | Right to left | | Chinese (Simplified) | `zh-CN` | Left to right | ## Setting it up [#setting-it-up] 1. Open **Settings > Brand Settings > Languages**. 2. Pick the **default language**. This is what new users see until they set their own preference. 3. Toggle on the languages you want available in the language switcher. 4. Save. You cannot disable your last remaining language, so enable the new one before turning the old one off. ## Choosing what to enable [#choosing-what-to-enable] Enable the languages you can actually support, not every language available. A customer who reads the portal in Polish will reasonably expect your support replies, terms, privacy policy, and help center content in Polish too, and those are yours to write. The interface translates. Your own content does not: brand name, legal pages, support details, and help center articles stay exactly as you wrote them. ## Right-to-left layout [#right-to-left-layout] Enabling Arabic switches the whole interface to a right-to-left layout for users on that language, including the sidebar and navigation. Preview it once before announcing it, particularly if you have a wide logo or a customized [dashboard theme](/addons/theme-editor). ## Common questions [#common-questions] **Does the language setting change the currency?** No. Currency is set once for the whole platform under [General Settings](/branding/branding). **Can an individual user override the default?** Yes. Each user can pick any language you have enabled, and their choice persists. **What happens to a user whose language I disable?** They fall back to your default language on their next visit. **Is this section locked during the trial?** No. Languages and [General Settings](/branding/branding) are both editable from day one. # Brand Settings (/branding/overview) **Settings > Brand Settings** is where you configure the platform your customers see. It is admin-only, and each section on the left of that page has its own guide here. ## The sections [#the-sections] | Section | What it controls | Guide | | --------------------- | ------------------------------------------------------------------------ | ------------------------------ | | General Settings | Brand name, logo, currency, default label, feature toggles, social links | [Read](/branding/branding) | | Languages | Which languages your portal offers and the default for new users | [Read](/branding/languages) | | Payment Options | Stripe, PayPal, and Airwallex credentials and what each gateway handles | [Read](/branding/payment) | | Domain Setup | Your custom domain, ownership proof, and DNS connection | [Read](/branding/domain) | | Email Setup | Sender name, sender address, and email authentication records | [Read](/branding/email) | | Support Settings | The support email, phone, contact form, and help center your users see | [Read](/branding/support) | | SSO Identity Settings | SpaceMedia as the login provider for an app you own | [Read](/branding/sso-identity) | | SSO Consumer Settings | An external identity provider as the login for your portal | [Read](/branding/sso-consumer) | | JWT SSO (Zendesk) | Signed handoff into your Zendesk help desk | [Read](/branding/jwt-sso) | | Terms of Services | Your terms content | [Read](/branding/terms) | | Privacy Policy | Your privacy content | [Read](/branding/privacy) | ## Suggested order [#suggested-order] Domain first, because DNS propagation is the only part you cannot rush. 1. **General Settings** and **Languages**, which are editable even during the trial. 2. **Domain Setup**, so propagation runs while you work on everything else. 3. **Email Setup**, which needs a connected domain before it will save. 4. **Payment Options**, then define what you sell under Settings > Upgrades. 5. **Support Settings**, **Terms of Services**, and **Privacy Policy** before you open registration. 6. **SSO** sections only if you are connecting an external login system. ## What is locked during the trial [#what-is-locked-during-the-trial] Until a card is authorized to start the 30-day free trial, these sections are read-only: Payment Options, Domain Setup, Email Setup, Support Settings, all three SSO sections, Terms of Services, and Privacy Policy. Release submission is blocked for the same reason. You can build a release and run the readiness checks, but submitting it returns "Authorize a card and start the 30-day free trial before submitting releases." until the trial is started. General Settings and Languages stay editable, so you can prepare your branding before committing. ## What is not here [#what-is-not-here] | Looking for | It lives in | | ------------------------------------- | ------------------------------------------------------------------ | | Dashboard colors, fonts, and layout | Settings > Theme Editor ([guide](/addons/theme-editor)) | | The design of outbound emails | Settings > Email Theme ([guide](/addons/email-theme-customizer)) | | Membership and pay-per-release prices | Settings > Upgrades | | Staff accounts and permissions | Settings > Members ([guide](/addons/members-management)) | | API credentials | Settings > DDEX Gateway ([guide](/addons/enterprise-delivery-api)) | | Your own password, 2FA, and sessions | Settings > Account Settings |
Secrets are write-only

Gateway secrets, OAuth client secrets, and JWT secrets are masked once saved and are never shown again. Leaving a secret field empty when you re-save keeps the stored value, so you only need to re-enter one when you are deliberately rotating it. Never paste a live secret into a support ticket or screenshot.

# Payment Options (/branding/payment) **Settings > Brand Settings > Payment Options** connects your own payment accounts. Money from your customers goes to your gateway, under your merchant account, in your currency. You can activate more than one gateway. Each has two switches: one for one-time payments and one for recurring memberships. ## The three gateways [#the-three-gateways] | Gateway | You provide | Where to get it | | ------------- | -------------------------------------- | ------------------------------------------------- | | **Stripe** | Publishable key and secret key | Stripe Dashboard > API Keys | | **PayPal** | Client ID and secret | PayPal Developer Dashboard > Apps and Credentials | | **Airwallex** | Client ID, API key, and webhook secret | Airwallex > Create API Key, then Create Webhook | Credentials are stored server-side and masked after saving. To keep an existing secret when re-saving, leave the field empty. ## Connecting a gateway [#connecting-a-gateway] Open **Settings > Brand Settings > Payment Options** and find the gateway card. Select **Configure Credentials** and paste in the values from your gateway account. Use the environment you actually intend to charge in. Switch **Activate gateway** on. That enables one-time card payments through it. Switch **Subscriptions** on if this gateway should also handle recurring membership checkouts. Activating a gateway turns this on by default, so switch it off if you do not want recurring charges on that gateway. Save, then confirm the secret fields are now masked. Run one small real transaction end to end and check it appears in your gateway dashboard. ## Airwallex setup [#airwallex-setup] Airwallex needs two extra things. **Scopes.** Enable all of these on the API key, or checkouts will fail in ways that are hard to diagnose: * Payment Acceptance: Read, Write * Billing Customers: Read, Write * Payment Sources: Read, Write * Subscriptions: Read, Write * Prices: Read, Write * Products: Read, Write * Billing Transactions: Read * Invoices: Read * Payment Disputes: Read **Webhook.** The Payment Options page shows the exact webhook URL to register in Airwallex. Copy it, create the webhook in the Airwallex web app, then paste the resulting webhook secret back into the dashboard. ## What you sell [#what-you-sell] Payment Options is the plumbing. The products are defined in **Settings > Upgrades**. | Product | What it is | | ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Memberships** | Recurring plans with their own price, billing cycle, royalty share, and limits on releases and artist profiles. Draft plans stay hidden, published plans appear to your customers, and archived plans leave the storefront while keeping existing subscribers intact. | | **Pay per release** | A price charged each time a customer submits a release, set per release type, with optional per-type discounts. | Add at least one pay-per-release option before switching pay-per-release on globally. An upgrade button only appears on a published membership when there is a higher published plan above it. ## Before you go live [#before-you-go-live] * Use production credentials for production and test credentials for testing. Never mix them. * Confirm your gateway account is on the right legal entity and settlement currency. * Test the success path, the cancel path, and an expired session. * If you offer both memberships and pay-per-release, test one of each.
Redirect parameters are not proof of payment

The query string a customer lands back on after checkout is navigation data only. Never treat it as confirmation that an order, subscription, add-on, or credit balance is paid, and never diagnose a failed payment from it. Your gateway dashboard and the platform's own order records are the truth.

## If a payment fails [#if-a-payment-fails] | Symptom | Check | | ------------------------------------------- | -------------------------------------------------------------------- | | Checkout will not open | Gateway is activated and credentials saved for the right environment | | Card is charged but nothing unlocks | Webhook is registered and the webhook secret matches | | Memberships fail but one-time payments work | The Subscriptions switch is on for that gateway | | Airwallex checkout errors on some steps | A required scope is missing from the API key | If a production gateway starts failing, switch that gateway off rather than repeatedly replacing secrets. Existing subscriptions stay manageable, and you can restore the working configuration from your gateway control panel. ## Common questions [#common-questions] **Can I use more than one gateway at once?** Yes. Activate each one you want, and set the Subscriptions switch per gateway. **Does SpaceMedia take the payment?** No. The gateway account is yours, and settlement goes to you. **Why is this section greyed out?** Payment Options stays read-only until the 30-day free trial is started with an authorized card. See [Getting Started](/gettingstarted). **Where do refunds happen?** In your gateway dashboard, as with any other charge on your merchant account. # Privacy Policy (/branding/privacy) **Settings > Brand Settings > Privacy Policy** holds the privacy notice shown on your portal. You are the controller for your customers' data, so this policy is yours to write and maintain. This guide is not legal advice. If you operate in the UK, EU, or another regulated market, have the final text reviewed. ## Update it before [#update-it-before] * Opening registration * Collecting payment details * Enabling support tickets or a help center * Adding analytics * Connecting an external identity provider ## What to cover [#what-to-cover] | Section | Include | | -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Who you are** | Legal entity name, address, support email, and a privacy contact | | **What you collect** | Registration and profile data, artist and release metadata, uploaded audio and artwork, payment metadata, support messages, and login records | | **Why** | The purpose and legal basis for each category | | **Processors** | Every third party involved: your hosting and distribution platform, payment gateways, email delivery, support tooling, analytics, and copyright checking | | **Transfers** | Whether data leaves your region and on what basis | | **Retention** | How long you keep account, catalog, support, and payment records after an account closes | | **Rights** | How users request access, correction, export, or deletion, and how quickly you respond | ## The processor list matters most [#the-processor-list-matters-most] This is the section people get wrong. Anything you switch on adds a processor. Enabling copyright checking, a payment gateway, or an external identity provider each change who handles your customers' data, so revisit this page whenever you change your configuration. ## Publishing [#publishing] 1. Draft and review outside the dashboard. 2. Paste the final text into the editor and save. 3. Confirm the page is linked from registration and checkout. 4. Open it on both your custom domain and your default workspace domain.
Do not use real examples

A privacy policy is a public page. Real customer names, support tickets, internal procedures, and anything resembling a credential do not belong in it.

## Common questions [#common-questions] **Can the policy be empty?** No. The editor requires content before it will save. **Am I the controller or the processor?** For your customers' data, you are the controller. SpaceMedia processes it to run the platform for you. Describe your own role accurately. **How often should I review it?** At minimum whenever you enable a new gateway, add-on, analytics tool, or identity provider, and once a year regardless. **Why is this section greyed out?** Legal sections are locked until the 30-day free trial is started with an authorized card. See [Getting Started](/gettingstarted). # SSO Consumer Settings (/branding/sso-consumer) **Settings > Brand Settings > SSO Consumer Settings** points your portal's login at an identity provider you already run, such as Okta, Auth0, Microsoft Entra ID, Keycloak, or your own OAuth 2 server. This is the inbound direction. For the reverse, where your portal is the provider, see [SSO Identity Settings](/branding/sso-identity). ## What you need from your provider [#what-you-need-from-your-provider] Register your SpaceMedia portal as an OAuth 2 application first. Your provider will give you the values below, and will ask you for a redirect URI, which the page shows you. | Field | What it is | | ------------------------- | ------------------------------------------------------------- | | **OAuth 2 Client ID** | The client identifier your provider issued | | **OAuth 2 Client Secret** | The matching secret. Masked after saving | | **Authorize URL** | The endpoint that starts the login flow | | **Token URL** | The endpoint that exchanges the authorization code for tokens | | **User info URL** | The endpoint that returns the signed-in user's profile | All four URLs must be HTTPS. ## Setting it up [#setting-it-up] 1. Register the application in your identity provider and copy the redirect URI from this page into it. 2. Paste the client ID, client secret, and the three endpoint URLs into the dashboard. 3. Save. The secret is masked once stored. 4. Test a full login round trip with a real account before making SSO the only way in. ## Scopes [#scopes] Request the minimum your provider needs to return an identifiable user, typically the equivalent of `openid`, `profile`, and `email`. Broad scopes give your portal access to data it does not use, which is a liability without a benefit. ## Test before you switch over [#test-before-you-switch-over]
Keep a way back in

Test SSO with a real account in a private browser window before you rely on it. If the provider is misconfigured and it is your only login path, you lock yourself out of your own dashboard along with everyone else.

Check that a user who has never signed in before is handled correctly, not just an account that already exists. ## If login fails [#if-login-fails] | Symptom | Usual cause | | ------------------------------------ | ---------------------------------------------------------------------------------------- | | Provider rejects the redirect | The redirect URI registered with your provider does not exactly match the one shown here | | Invalid client | The client secret was rotated at the provider and not updated here | | Login succeeds, portal does not | The user info URL is wrong, or it returns a shape without a usable email | | Works for you, fails for a colleague | Their account is not assigned to the application in your provider | ## Common questions [#common-questions] **Do users keep their password on my portal?** Once SSO is in use, authentication happens at your provider. Manage credential policy there. **Can I use both consumer SSO and normal login?** Test with both available before you remove any path, and never remove the fallback until SSO is proven with more than one account. **Which providers are supported?** Any standard OAuth 2 provider that exposes authorize, token, and user info endpoints. **Why is this section greyed out?** SSO sections are locked until the 30-day free trial is started with an authorized card. See [Getting Started](/gettingstarted). # SSO Identity Settings (/branding/sso-identity) **Settings > Brand Settings > SSO Identity Settings** turns your portal into the login provider for another application you own. Your customers sign in on your portal, and your app receives their identity. This is the outbound direction. For the reverse, where your portal defers to an existing identity provider, see [SSO Consumer Settings](/branding/sso-consumer). ## When you would use this [#when-you-would-use-this] You already run something else your customers use: a fan app, a merch store, a members area, a community. Rather than making them create a second account, they sign in with the account they already have on your portal. If you have no second application, skip this section entirely. ## What the page gives you [#what-the-page-gives-you] Four read-only endpoints, which you copy into your application's OAuth configuration: | Endpoint | Purpose | | ----------------- | ---------------------------------------------------- | | **Authorize URL** | Where the login flow starts | | **Token URL** | Where the authorization code is exchanged for tokens | | **Profile API** | Where your app resolves the signed-in user | | **Logout API** | Where the connected session is ended | ## Setting it up [#setting-it-up] Enter the **Client redirect URI**: the URL in your application that users are sent back to after a successful login. It must be HTTPS and must match exactly what your app sends. Select **Generate client**. A client ID and a client secret are created for your organization. Copy the client secret immediately and store it in your secret manager. It is not shown again after the page reloads. Copy the four endpoint URLs into your application's OAuth 2 configuration, along with the client ID and secret. Switch **Identity SSO** on, then test a full login round trip before telling any customer about it.
The secret is shown once

If you lose the client secret, generating the client again issues a new one. That immediately invalidates the old secret, so plan the rotation into a deployment window rather than doing it mid-day.

## Testing the round trip [#testing-the-round-trip] 1. Sign out of both your portal and your application. 2. Start the login from your application, not from the portal. 3. Confirm you are redirected to your portal, can sign in, and land back on your redirect URI. 4. Confirm your application resolves the correct user through the Profile API. 5. Sign out and confirm the session actually ends. ## If login fails [#if-login-fails] | Symptom | Usual cause | | --------------------------------- | ------------------------------------------------------------------------------------------------------ | | Redirect URI mismatch error | The URI in your app differs from the saved one, often by a trailing slash or `http` instead of `https` | | Invalid client error | The client secret was rotated and your app still holds the old one | | Login works but the user is wrong | Your app is caching a session. Clear it and retest from a clean browser profile | | Nothing happens when SSO is on | The client was never generated, or Identity SSO is switched off | ## Common questions [#common-questions] **Can I connect more than one application?** The page issues one client per organization. Point multiple applications at it only if they can safely share the same client credentials and redirect URI. **Does this change how staff sign in to the dashboard?** No. This is about your application receiving identities from your portal. **Is this the same as the Delivery API?** No. This is end-user login. Machine-to-machine access uses API credentials, documented in [Authentication](/delivery-api/authentication). **Why is this section greyed out?** SSO sections are locked until the 30-day free trial is started with an authorized card. See [Getting Started](/gettingstarted). # Support Settings (/branding/support) **Settings > Brand Settings > Support Settings** is where your customers are sent when they need help. Four fields, all shown inside the portal. ## Fields [#fields] | Field | Notes | | -------------------- | --------------------------------------------------------------------------------------------------------------------------------- | | **Support email** | The primary support inbox shown to users. Use a shared, monitored address, not a personal one. | | **Support phone** | Country code plus number. Only publish one if you can consistently answer it. | | **Contact form URL** | A direct link to your contact form, if you run one. | | **Help center URL** | Where users find self-service content. Point this at your [Knowledge Base Manager](/addons/knowledge-base-manager) if you use it. | Leave a field empty rather than filling it with a placeholder. An unanswered phone number costs more trust than no phone number. ## Make the inbox work [#make-the-inbox-work] A support address that goes to one person's mailbox becomes a problem the first time they take a holiday. Before you publish it: * Route it to a shared inbox or ticketing system, not an individual. * Decide who owns first response and what the response window is. * If you have installed [Support Desk Manager](/addons/support-desk-manager), point customers at the in-portal ticket area instead, so context stays attached to the account. ## What to ask for [#what-to-ask-for] Support requests resolve faster when the first message already contains the right context. | Issue type | Ask for | | ----------------------- | ---------------------------------------------------------------------------------------------- | | Release problem | Release title, current status, affected tracks, the account email, and when it happened | | Track or upload problem | Track title, file format, upload time, and the exact validation message | | Payment problem | Amount, currency, timestamp, and any receipt or order reference shown to the customer | | Access problem | Account email, the role they expect, the page they cannot reach, and when they last had access |
Never ask for secrets

Passwords, API secrets, bearer tokens, gateway keys, and full card numbers are never needed to diagnose an issue, and asking for them trains your customers to hand them over. Screenshots should be masked before they are attached to a ticket.

## Common questions [#common-questions] **Do these details appear on my public marketing site?** No. They are shown inside the portal to signed-in users. **Can different customers see different support contacts?** No. These are platform-wide settings. **Should I fill in both the contact form and the help center?** If you have both, yes. The help center deflects repeat questions and the contact form catches everything else. **Why is this section greyed out?** Support Settings is locked until the 30-day free trial is started with an authorized card. See [Getting Started](/gettingstarted). # Terms of Service (/branding/terms) **Settings > Brand Settings > Terms of Services** holds the terms your customers agree to. The editor is rich text, and the saved content is published on your portal's legal page, linked from registration and checkout. These are your terms with your customers. They are not a copy of your agreement with SpaceMedia, and this guide is not legal advice. ## Update them before [#update-them-before] * Opening registration * Publishing a membership plan or pay-per-release pricing * Enabling credits, add-ons, or copyright wallet top-ups * Accepting release submissions * Launching on a custom domain ## What to cover [#what-to-cover] | Section | Include | | ----------------------- | ----------------------------------------------------------------------------------------------------------------- | | **Account access** | Who may register, who may manage an artist account, and when you can suspend access | | **Catalog obligations** | Metadata accuracy, rights ownership, contributor credits, what your review process checks, and prohibited content | | **Payments** | Subscription terms, pay-per-release charges, credits, refunds, failed payments, and tax handling | | **Revenue splits** | Who confirms a split, what each beneficiary is responsible for, and the conditions for payout | | **Takedowns** | How a release is removed, who can request it, and how long it takes | | **Support** | How to reach you, response expectations, and escalation | The catalog and payments sections are the ones that get tested. Be specific about what happens when a release is rejected and what happens when a payment fails. ## Editing safely [#editing-safely] * Draft and review the copy outside the dashboard, then paste the final version in. * Scripts and unsupported HTML are not accepted in the editor. * Check the published page on both your custom domain and your default workspace domain. * Keep a dated copy of every version you publish. You will eventually need to show what was in force on a given day.
These are customer-facing

Anyone who visits your portal can read this page. Keep internal pricing notes, support procedures, partner terms, and real customer disputes out of it.

## Common questions [#common-questions] **Can the terms be empty?** No. The editor requires content before it will save. **Are customers asked to re-accept when I update them?** Publishing updates the page. If a change is material, tell your customers directly rather than relying on them noticing. **Can I have different terms per language?** The page holds one version. If you serve multiple [languages](/branding/languages), decide which one is authoritative and say so in the text. **Why is this section greyed out?** Legal sections are locked until the 30-day free trial is started with an authorized card. See [Getting Started](/gettingstarted). # Create Account Label (/delivery-api/endpoints/account-settings/createAccountLabel) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Create Label (/delivery-api/endpoints/account-settings/createLabel) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Delete Account Session (/delivery-api/endpoints/account-settings/deleteAccountSession) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # View Current Account Settings (/delivery-api/endpoints/account-settings/getCurrentAccountSettings) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # View Label (/delivery-api/endpoints/account-settings/getLabel) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # List Account Sessions (/delivery-api/endpoints/account-settings/listAccountSessions) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # List Labels (/delivery-api/endpoints/account-settings/listLabels) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Update Notification Preferences (/delivery-api/endpoints/account-settings/updateNotificationPreferences) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Update Personal Information (/delivery-api/endpoints/account-settings/updatePersonalInformation) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Activate Add-On (/delivery-api/endpoints/add-ons/activateAddon) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Create Add-On Checkout (/delivery-api/endpoints/add-ons/createAddonCheckout) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Deactivate Add-On (/delivery-api/endpoints/add-ons/deactivateAddon) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # View Add-On Checkout Status (/delivery-api/endpoints/add-ons/getAddonCheckoutStatus) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Install Add-On (/delivery-api/endpoints/add-ons/installAddon) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Uninstall Add-On (/delivery-api/endpoints/add-ons/uninstallAddon) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Create Artist (/delivery-api/endpoints/artists/createArtist) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Delete Artist (/delivery-api/endpoints/artists/deleteArtist) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # List Artists (/delivery-api/endpoints/artists/listArtists) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Update Artist (/delivery-api/endpoints/artists/updateArtist) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Create API Token (/delivery-api/endpoints/authentication/createApiToken) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Get Authenticated API Context (/delivery-api/endpoints/authentication/getAuthenticatedApiContext) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Cancel Activation Trial (/delivery-api/endpoints/billing-and-checkouts/cancelActivationTrial) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Cancel Billing Subscription (/delivery-api/endpoints/billing-and-checkouts/cancelBillingSubscription) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Cancel Subscription (/delivery-api/endpoints/billing-and-checkouts/cancelSubscription) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Create Airwallex Release Checkout (/delivery-api/endpoints/billing-and-checkouts/createAirwallexReleaseCheckout) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Create Airwallex Subscription Checkout (/delivery-api/endpoints/billing-and-checkouts/createAirwallexSubscriptionCheckout) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Create Credits Checkout (/delivery-api/endpoints/billing-and-checkouts/createCreditsCheckout) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Create Embedded Payment Method Setup (/delivery-api/endpoints/billing-and-checkouts/createEmbeddedPaymentMethodSetup) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Create Payment Method Management Session (/delivery-api/endpoints/billing-and-checkouts/createPaymentMethodManagementSession) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Create PayPal Release Checkout (/delivery-api/endpoints/billing-and-checkouts/createPaypalReleaseCheckout) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Create PayPal Subscription Checkout (/delivery-api/endpoints/billing-and-checkouts/createPaypalSubscriptionCheckout) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Create Stripe Release Checkout (/delivery-api/endpoints/billing-and-checkouts/createStripeReleaseCheckout) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Create Stripe Subscription Checkout (/delivery-api/endpoints/billing-and-checkouts/createStripeSubscriptionCheckout) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Delete Payment Method (/delivery-api/endpoints/billing-and-checkouts/deletePaymentMethod) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Download Billing Invoice PDF (/delivery-api/endpoints/billing-and-checkouts/downloadBillingInvoicePdf) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # View Billing Overview (/delivery-api/endpoints/billing-and-checkouts/getBillingOverview) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # List Subscriptions (/delivery-api/endpoints/billing-and-checkouts/listSubscriptions) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Resume Billing Subscription (/delivery-api/endpoints/billing-and-checkouts/resumeBillingSubscription) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Resume Subscription (/delivery-api/endpoints/billing-and-checkouts/resumeSubscription) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Set Default Payment Method (/delivery-api/endpoints/billing-and-checkouts/setDefaultPaymentMethod) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Start PayPal Payment Method Setup (/delivery-api/endpoints/billing-and-checkouts/startPaypalPaymentMethodSetup) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Start Stripe Payment Method Setup (/delivery-api/endpoints/billing-and-checkouts/startStripePaymentMethodSetup) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Verify Credits Checkout (/delivery-api/endpoints/billing-and-checkouts/verifyCreditsCheckout) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Verify PayPal Payment Method Setup (/delivery-api/endpoints/billing-and-checkouts/verifyPaypalPaymentMethodSetup) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Verify Release Checkout (/delivery-api/endpoints/billing-and-checkouts/verifyReleaseCheckout) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Verify Stripe Payment Method Setup (/delivery-api/endpoints/billing-and-checkouts/verifyStripePaymentMethodSetup) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Verify Embedded Stripe Setup Intent (/delivery-api/endpoints/billing-and-checkouts/verifyStripeSetupIntent) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Verify Subscription Checkout (/delivery-api/endpoints/billing-and-checkouts/verifySubscriptionCheckout) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Create Copyright Wallet Top-Up (/delivery-api/endpoints/copyright/createCopyrightWalletTopUp) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # View Copyright Release (/delivery-api/endpoints/copyright/getCopyrightRelease) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # View Copyright Statistics (/delivery-api/endpoints/copyright/getCopyrightStatistics) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # View Copyright Summary (/delivery-api/endpoints/copyright/getCopyrightSummary) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Check Copyright Wallet Top-Up Status (/delivery-api/endpoints/copyright/getCopyrightTopUpStatus) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # View Copyright Wallet (/delivery-api/endpoints/copyright/getCopyrightWallet) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # List Copyright Releases (/delivery-api/endpoints/copyright/listCopyrightReleases) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # List Copyright Top-Ups (/delivery-api/endpoints/copyright/listCopyrightTopUps) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # List Copyright Wallet Transactions (/delivery-api/endpoints/copyright/listCopyrightWalletTransactions) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Cancel DDEX message operation (/delivery-api/endpoints/ddex/cancelDdexMessage) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Confirm DDEX message claim (/delivery-api/endpoints/ddex/confirmDdexMessageClaim) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Create DDEX acknowledgement (/delivery-api/endpoints/ddex/createDdexAcknowledgement) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Create DDEX delivery batch (/delivery-api/endpoints/ddex/createDdexBatch) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Create DDEX partner connection (/delivery-api/endpoints/ddex/createDdexConnection) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Create DDEX deal profile (/delivery-api/endpoints/ddex/createDdexDealProfile) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Create DDEX delivery (/delivery-api/endpoints/ddex/createDdexDelivery) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Create DDEX export (/delivery-api/endpoints/ddex/createDdexExport) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Create native DDEX import (/delivery-api/endpoints/ddex/createDdexImport) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Create DDEX sender identity (/delivery-api/endpoints/ddex/createDdexSenderIdentity) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Download DDEX XML payload (/delivery-api/endpoints/ddex/downloadDdexPayload) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Download DDEX delivery resource (/delivery-api/endpoints/ddex/downloadDdexResource) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Download DDEX validation report (/delivery-api/endpoints/ddex/downloadDdexValidationReport) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Get native DDEX import (/delivery-api/endpoints/ddex/getDdexImport) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Get DDEX message operation (/delivery-api/endpoints/ddex/getDdexMessage) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Get DDEX compatibility matrix (/delivery-api/endpoints/ddex/getDdexStandards) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Get DDEX Web Service feed (/delivery-api/endpoints/ddex/getDdexWebServiceFeed) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # List DDEX delivery batches (/delivery-api/endpoints/ddex/listDdexBatches) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # List DDEX partner connections (/delivery-api/endpoints/ddex/listDdexConnections) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # List DDEX deal profiles (/delivery-api/endpoints/ddex/listDdexDealProfiles) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # List native DDEX imports (/delivery-api/endpoints/ddex/listDdexImports) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # List DDEX message operations (/delivery-api/endpoints/ddex/listDdexMessages) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # List DDEX sender identities (/delivery-api/endpoints/ddex/listDdexSenderIdentities) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Request DDEX connection activation (/delivery-api/endpoints/ddex/requestDdexConnectionActivation) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Start DDEX connection health check (/delivery-api/endpoints/ddex/startDdexConnectionHealthCheck) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Retry DDEX message operation (/delivery-api/endpoints/ddex/startDdexMessageRetry) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Rotate DDEX connection secret (/delivery-api/endpoints/ddex/updateDdexConnectionSecret) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Upload native DDEX message (/delivery-api/endpoints/ddex/uploadNativeDdexMessage) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Validate DDEX operation (/delivery-api/endpoints/ddex/validateDdexOperation) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # View Email Theme Profile (/delivery-api/endpoints/email-theme/getEmailThemeProfile) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Preview Email Theme (/delivery-api/endpoints/email-theme/previewEmailTheme) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Publish Email Theme (/delivery-api/endpoints/email-theme/publishEmailTheme) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Save Email Theme Draft (/delivery-api/endpoints/email-theme/saveEmailThemeDraft) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Create enterprise webhook (/delivery-api/endpoints/enterprise-webhooks/createEnterpriseWebhook) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Replay enterprise webhook delivery (/delivery-api/endpoints/enterprise-webhooks/createEnterpriseWebhookReplay) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Create test webhook delivery (/delivery-api/endpoints/enterprise-webhooks/createEnterpriseWebhookTest) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Delete enterprise webhook (/delivery-api/endpoints/enterprise-webhooks/deleteEnterpriseWebhook) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # List webhook delivery attempts (/delivery-api/endpoints/enterprise-webhooks/listEnterpriseWebhookDeliveries) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # List enterprise webhooks (/delivery-api/endpoints/enterprise-webhooks/listEnterpriseWebhooks) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Update enterprise webhook (/delivery-api/endpoints/enterprise-webhooks/updateEnterpriseWebhook) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Rotate webhook signing secret (/delivery-api/endpoints/enterprise-webhooks/updateEnterpriseWebhookSecret) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Submit Platform Feedback (/delivery-api/endpoints/feedback/submitPlatformFeedback) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Cancel Member Invitation (/delivery-api/endpoints/members/cancelMemberInvitation) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Create Member Role (/delivery-api/endpoints/members/createMemberRole) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Get Member (/delivery-api/endpoints/members/getMember) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Invite Members (/delivery-api/endpoints/members/inviteMembers) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # List Member Invitations (/delivery-api/endpoints/members/listMemberInvitations) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # List Member Permissions (/delivery-api/endpoints/members/listMemberPermissions) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # List Member Roles (/delivery-api/endpoints/members/listMemberRoles) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # List Members (/delivery-api/endpoints/members/listMembers) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Remove Member (/delivery-api/endpoints/members/removeMember) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Resend Member Invitation (/delivery-api/endpoints/members/resendMemberInvitation) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Suspend Member (/delivery-api/endpoints/members/suspendMember) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Unsuspend Member (/delivery-api/endpoints/members/unsuspendMember) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Update Member (/delivery-api/endpoints/members/updateMember) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Update Member Role (/delivery-api/endpoints/members/updateMemberRole) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Update Member Role Permissions (/delivery-api/endpoints/members/updateMemberRolePermissions) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # View Upgrade Options (/delivery-api/endpoints/plans-and-upgrades/getUpgradeOptions) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # List Membership Plans (/delivery-api/endpoints/plans-and-upgrades/listMembershipPlans) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # List Pay-Per-Release Plans (/delivery-api/endpoints/plans-and-upgrades/listPayPerReleasePlans) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # List Countries (/delivery-api/endpoints/reference-data/listCountries) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # List Distribution Channels (/delivery-api/endpoints/reference-data/listReleaseDistributionChannels) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # List Release Territories (/delivery-api/endpoints/reference-data/listReleaseTerritories) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # List Organization Release Reviews (/delivery-api/endpoints/release-review/listOrganizationReleaseReviews) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # List Sent Review Releases (/delivery-api/endpoints/release-review/listSentReviewReleases) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # List Submitted Review Releases (/delivery-api/endpoints/release-review/listSubmittedReviewReleases) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Create Release (/delivery-api/endpoints/releases/createRelease) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Delete Release (/delivery-api/endpoints/releases/deleteRelease) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # View Release (/delivery-api/endpoints/releases/getRelease) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Get Release Edit Options (/delivery-api/endpoints/releases/getReleaseEditOptions) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # View Release Readiness Checks (/delivery-api/endpoints/releases/getReleaseReadinessChecks) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Import Releases From Music URLs (/delivery-api/endpoints/releases/importReleasesFromMusicUrls) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # List Release Tracks (/delivery-api/endpoints/releases/listReleaseTracks) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # List Releases (/delivery-api/endpoints/releases/listReleases) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Reorder Release Tracks (/delivery-api/endpoints/releases/reorderReleaseTracks) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Submit Release (/delivery-api/endpoints/releases/submitRelease) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Update Release (/delivery-api/endpoints/releases/updateRelease) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Update Release Cover Art (/delivery-api/endpoints/releases/updateReleaseCoverArt) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Update Release Distribution (/delivery-api/endpoints/releases/updateReleaseDistribution) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Update Release License (/delivery-api/endpoints/releases/updateReleaseLicense) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Validate Legal Credit Name (/delivery-api/endpoints/releases/validateLegalCreditName) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Confirm Revenue Split (/delivery-api/endpoints/revenue-splits/confirmRevenueSplit) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Create Revenue Split (/delivery-api/endpoints/revenue-splits/createRevenueSplit) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # List Revenue Splits (/delivery-api/endpoints/revenue-splits/listRevenueSplits) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Update Revenue Split (/delivery-api/endpoints/revenue-splits/updateRevenueSplit) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Create Smartlink (/delivery-api/endpoints/smartlinks/createSmartlink) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Delete Smartlink (/delivery-api/endpoints/smartlinks/deleteSmartlink) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # View Smartlink (/delivery-api/endpoints/smartlinks/getSmartlink) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # View Smartlink Analytics (/delivery-api/endpoints/smartlinks/getSmartlinkAnalytics) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # View Smartlink Preferences (/delivery-api/endpoints/smartlinks/getSmartlinkPreferences) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # List Smartlinks (/delivery-api/endpoints/smartlinks/listSmartlinks) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Sync Smartlink (/delivery-api/endpoints/smartlinks/syncSmartlink) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Update My Smartlink Preferences (/delivery-api/endpoints/smartlinks/updateMySmartlinkPreferences) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Update Organization Smartlink Preferences (/delivery-api/endpoints/smartlinks/updateOrganizationSmartlinkPreferences) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Update Smartlink (/delivery-api/endpoints/smartlinks/updateSmartlink) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Update Smartlink Status (/delivery-api/endpoints/smartlinks/updateSmartlinkStatus) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # View Theme Profile (/delivery-api/endpoints/theme-editor/getThemeEditorProfile) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Publish Theme Profile (/delivery-api/endpoints/theme-editor/publishThemeProfile) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Save Theme Draft (/delivery-api/endpoints/theme-editor/saveThemeDraft) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Assign Track to Release (/delivery-api/endpoints/tracks/assignTrackToRelease) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Create Track (/delivery-api/endpoints/tracks/createTrack) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Delete Track (/delivery-api/endpoints/tracks/deleteTrack) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Download Track Document (/delivery-api/endpoints/tracks/downloadTrackDocument) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Get Track Upload Status (/delivery-api/endpoints/tracks/getTrackUploadStatus) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # List Tracks (/delivery-api/endpoints/tracks/listTracks) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Remove Track from Release (/delivery-api/endpoints/tracks/removeTrackFromRelease) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Submit Track Document (/delivery-api/endpoints/tracks/submitTrackDocument) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Update Track (/delivery-api/endpoints/tracks/updateTrack) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Upload Track Audio (/delivery-api/endpoints/tracks/uploadTrackAudio) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Upload Track Audio Chunk (/delivery-api/endpoints/tracks/uploadTrackAudioChunk) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Create User (/delivery-api/endpoints/users/createUser) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Get Organization User (/delivery-api/endpoints/users/getOrganizationUser) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # List User Artists (/delivery-api/endpoints/users/listUserArtists) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # List User Releases (/delivery-api/endpoints/users/listUserReleases) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # List User Revenue (/delivery-api/endpoints/users/listUserRevenue) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # List User Revenue Splits (/delivery-api/endpoints/users/listUserSplits) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # List User Tracks (/delivery-api/endpoints/users/listUserTracks) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # List Users (/delivery-api/endpoints/users/listUsers) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Suspend User (/delivery-api/endpoints/users/suspendUser) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Unsuspend User (/delivery-api/endpoints/users/unsuspendUser) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Update User (/delivery-api/endpoints/users/updateUser) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Update User Profile Photo (/delivery-api/endpoints/users/updateUserProfilePhoto) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Approve or Deny WordPress Catalog Access (/delivery-api/endpoints/wordpress-oauth/decideWordPressOAuthAuthorization) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Exchange or Refresh a WordPress OAuth Token (/delivery-api/endpoints/wordpress-oauth/exchangeWordPressOAuthToken) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Read the Authorized WordPress Catalog (/delivery-api/endpoints/wordpress-oauth/getWordPressOAuthCatalog) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Register a WordPress Installation (/delivery-api/endpoints/wordpress-oauth/registerWordPressOAuthInstallation) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Revoke WordPress Catalog Access (/delivery-api/endpoints/wordpress-oauth/revokeWordPressOAuthConnection) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Review WordPress Catalog Access (/delivery-api/endpoints/wordpress-oauth/showWordPressOAuthAuthorization) {/* Generated from api-reference\/openapi.json. Run npm run generate:api to refresh. */} # Append one idempotent retained comment to a tenant anomaly case. (/reports-api/endpoints/anomalies/commentPlatformAnomalyCase) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Return one tenant anomaly case with its immutable comment timeline. (/reports-api/endpoints/anomalies/getPlatformAnomalyCase) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Return tenant anomaly queue and suppression-expiry metrics. (/reports-api/endpoints/anomalies/getPlatformAnomalyMetrics) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # List bounded tenant-scoped anomaly cases for authorized operators. (/reports-api/endpoints/anomalies/listPlatformAnomalyCases) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Issue one API client and return its plaintext secret once. (/reports-api/endpoints/api-clients/createPlatformApiClient) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Disable a client and revoke existing bearer tokens. (/reports-api/endpoints/api-clients/disablePlatformApiClient) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Re-enable a non-expired disabled client. (/reports-api/endpoints/api-clients/enablePlatformApiClient) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # List opaque bearer-token metadata for one client. (/reports-api/endpoints/api-clients/listPlatformApiClientTokens) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # List opaque API-client metadata for the current external tenant. (/reports-api/endpoints/api-clients/listPlatformApiClients) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Replace client scopes and revoke existing bearer tokens. (/reports-api/endpoints/api-clients/replacePlatformApiClientScopes) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Terminally revoke one client and all active bearer tokens. (/reports-api/endpoints/api-clients/revokePlatformApiClient) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Revoke one client-bound bearer token. (/reports-api/endpoints/api-clients/revokePlatformApiClientToken) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Rotate a client secret with a bounded overlap window. (/reports-api/endpoints/api-clients/rotatePlatformApiClient) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Change a client name and expiry authority. (/reports-api/endpoints/api-clients/updatePlatformApiClient) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Verify bearer authentication, tenant binding, and the tenant:read scope. (/reports-api/endpoints/api-session/getPlatformApiSession) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Approve at most twenty exact catalog candidates with fresh MFA and one idempotent transaction. (/reports-api/endpoints/catalog-review/bulkApproveExactPlatformCatalogMatches) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Approve, reject, or hold one match with fresh MFA and idempotency. (/reports-api/endpoints/catalog-review/decidePlatformCatalogMatch) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Return one tenant-owned catalog entity with its latest verified snapshot and identifiers. (/reports-api/endpoints/catalog-review/getPlatformCatalogEntity) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Return one opaque catalog match case and its latest reviewed state. (/reports-api/endpoints/catalog-review/getPlatformCatalogMatch) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Return tenant-scoped review queue and accounting-suspense metrics. (/reports-api/endpoints/catalog-review/getPlatformCatalogMatchMetrics) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Link one existing tenant dispute to a catalog match case as immutable suspense evidence. (/reports-api/endpoints/catalog-review/linkPlatformCatalogMatchDispute) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # List tenant-scoped catalog entities with their latest verified snapshots. (/reports-api/endpoints/catalog-review/listPlatformCatalogEntities) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # List verified candidate snapshots for one catalog match case. (/reports-api/endpoints/catalog-review/listPlatformCatalogMatchCandidates) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # List tenant-scoped catalog match cases for authorized human review. (/reports-api/endpoints/catalog-review/listPlatformCatalogMatches) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Acknowledge one open dispute with distinct-actor and idempotency controls. (/reports-api/endpoints/disputes/acknowledgePlatformDispute) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Assign or reassign one acknowledged open dispute to an approved tenant finance user. (/reports-api/endpoints/disputes/assignPlatformDispute) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Consume one signed evidence access after immutable object verification. (/reports-api/endpoints/disputes/downloadPlatformDisputeEvidence) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Escalate one proposed resolution to a strictly higher tenant finance role. (/reports-api/endpoints/disputes/escalatePlatformDispute) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Return verified immutable dispute, event, outcome, and evidence metadata. (/reports-api/endpoints/disputes/getPlatformDispute) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Grant one short-lived signed and actor-bound evidence download. (/reports-api/endpoints/disputes/grantPlatformDisputeEvidenceAccess) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Start one immutable investigation as the current verified dispute assignee. (/reports-api/endpoints/disputes/investigatePlatformDispute) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # List one bounded page of immutable internal dispute notes. (/reports-api/endpoints/disputes/listPlatformDisputeNotes) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # List tenant-scoped dispute summaries for approved external finance readers. (/reports-api/endpoints/disputes/listPlatformDisputes) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Propose one immutable outcome as the current assignee after investigation. (/reports-api/endpoints/disputes/proposePlatformDisputeResolution) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Append one immutable inbound or outbound external communication under recent MFA. (/reports-api/endpoints/disputes/recordPlatformDisputeCommunication) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Append one immutable internal-only dispute note. (/reports-api/endpoints/disputes/recordPlatformDisputeNote) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Reject or approve withdrawal through an exact maker-checker hold reversal. (/reports-api/endpoints/disputes/releasePlatformDispute) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Create one fresh child dispute from an immutable rejected, withdrawn or upheld case. (/reports-api/endpoints/disputes/reopenPlatformDispute) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Submit one verified-evidence statement dispute and post its capped suspense hold. (/reports-api/endpoints/disputes/submitPlatformDispute) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Uphold only after complete published correction and replacement evidence. (/reports-api/endpoints/disputes/upholdPlatformDispute) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Verify, malware-scan, immutably store, and approve one dispute evidence item. (/reports-api/endpoints/disputes/uploadPlatformDisputeEvidence) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Cancel an export only while it remains queued using exports:write authority. (/reports-api/endpoints/exports/cancelPlatformExport) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Cancel a queued export as a recently step-up-authenticated external-tenant member. (/reports-api/endpoints/exports/cancelPlatformExportAsHuman) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Queue one bounded external-tenant export using exports:write authority. (/reports-api/endpoints/exports/createPlatformExport) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Queue one bounded export as a recently step-up-authenticated external-tenant member. (/reports-api/endpoints/exports/createPlatformExportAsHuman) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Download one complete ready export using exports:read authority. (/reports-api/endpoints/exports/downloadPlatformExport) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Download one complete ready export with recent non-recovery MFA step-up. (/reports-api/endpoints/exports/downloadPlatformExportAsHuman) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Poll safe export lifecycle state using exports:write authority. (/reports-api/endpoints/exports/getPlatformExport) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Poll safe export lifecycle state as an authorized external-tenant member. (/reports-api/endpoints/exports/getPlatformExportAsHuman) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # List a bounded page of safe export lifecycle states using exports:read authority. (/reports-api/endpoints/exports/listPlatformExports) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # List a bounded page of safe export lifecycle states as an authorized external-tenant member. (/reports-api/endpoints/exports/listPlatformExportsAsHuman) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Revoke a ready export using exports:write authority without delivering its artifact. (/reports-api/endpoints/exports/revokePlatformExport) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Revoke a ready export as a recently step-up-authenticated external-tenant member. (/reports-api/endpoints/exports/revokePlatformExportAsHuman) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Accept an invitation as the current step-up-authenticated identity. (/reports-api/endpoints/identity/acceptExistingPlatformInvitation) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Accept an invitation and create a new verified identity. (/reports-api/endpoints/identity/acceptNewPlatformInvitation) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Return the current opaque identity and tenant session. (/reports-api/endpoints/identity/getPlatformIdentitySession) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # List the current identity's bounded tenant session history. (/reports-api/endpoints/identity/listPlatformIdentitySessions) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Establish a tenant-scoped human session. (/reports-api/endpoints/identity/loginPlatformIdentity) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Revoke the current platform session. (/reports-api/endpoints/identity/logoutPlatformIdentity) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Revoke another owned session after fresh non-recovery step-up. (/reports-api/endpoints/identity/revokePlatformIdentitySession) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Cancel an eligible active import without deleting retained evidence. (/reports-api/endpoints/imports/cancelPlatformImport) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Create one tenant-owned import and expected immutable source manifest. (/reports-api/endpoints/imports/createPlatformImport) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Issue one short-lived tenant-bound resumable upload authority. (/reports-api/endpoints/imports/createPlatformImportUploadSession) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Return opaque import workflow and bounded profiling evidence. (/reports-api/endpoints/imports/getPlatformImport) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Return bounded mapping suggestions without machine approval authority. (/reports-api/endpoints/imports/getPlatformImportMappingSuggestions) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Enqueue durable profiling from verified immutable source evidence. (/reports-api/endpoints/imports/profilePlatformImport) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Approve and remember one reviewed mapping under recent MFA when maker-checker is disabled. (/reports-api/endpoints/mapping-review/approvePlatformMapping) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Approve an exact proposal as a distinct checker under recent MFA. (/reports-api/endpoints/mapping-review/approvePlatformMappingProposal) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Return the tenant maker-checker policy and latest immutable proposal. (/reports-api/endpoints/mapping-review/getPlatformMappingProposal) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Return profiled source evidence for one human mapping review. (/reports-api/endpoints/mapping-review/getPlatformMappingReview) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # List bounded tenant imports awaiting human mapping review. (/reports-api/endpoints/mapping-review/listPlatformMappingReviews) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Validate and preview one declarative mapping without saving it. (/reports-api/endpoints/mapping-review/previewPlatformMapping) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Submit exact mapping-preview evidence for a distinct checker under recent MFA. (/reports-api/endpoints/mapping-review/proposePlatformMapping) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Reject an exact proposal as a distinct checker under recent MFA. (/reports-api/endpoints/mapping-review/rejectPlatformMappingProposal) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Verify a TOTP challenge and elevate the current session. (/reports-api/endpoints/mfa/challengePlatformMfa) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Confirm initial TOTP enrollment and return recovery codes once. (/reports-api/endpoints/mfa/confirmPlatformMfaEnrollment) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Atomically replace the active TOTP factor after fresh non-recovery step-up. (/reports-api/endpoints/mfa/confirmPlatformMfaReplacement) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Consume one recovery code without satisfying sensitive step-up. (/reports-api/endpoints/mfa/recoverPlatformMfa) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Start initial TOTP enrollment and return the secret once. (/reports-api/endpoints/mfa/startPlatformMfaEnrollment) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Start TOTP factor replacement after fresh non-recovery step-up. (/reports-api/endpoints/mfa/startPlatformMfaReplacement) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Exchange one tenant-bound client credential for a short-lived bearer token. (/reports-api/endpoints/oauth/exchangePlatformClientCredential) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Create route authority after a distinct finance identity approves with recent MFA. (/reports-api/endpoints/payout-operations/approvePlatformPayoutAlertRouteProposal) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Return one verified opaque payout-alert route authority. (/reports-api/endpoints/payout-operations/getPlatformPayoutAlertRoute) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Return one verified retained payout-alert route proposal. (/reports-api/endpoints/payout-operations/getPlatformPayoutAlertRouteProposal) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Return one verified payout exception and its immutable investigation history. (/reports-api/endpoints/payout-operations/getPlatformPayoutException) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Append an immutable finding without changing payout or queue state. (/reports-api/endpoints/payout-operations/investigatePlatformPayoutException) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # List retained maker-checker route proposals for external finance readers. (/reports-api/endpoints/payout-operations/listPlatformPayoutAlertRouteProposals) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # List reviewed tenant alert routes without addresses, credentials, hashes, or internal identifiers. (/reports-api/endpoints/payout-operations/listPlatformPayoutAlertRoutes) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # List bounded secret-safe payout ambiguity and dead-letter cases for external finance readers. (/reports-api/endpoints/payout-operations/listPlatformPayoutExceptions) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Propose opaque route authority without creating an active delivery route. (/reports-api/endpoints/payout-operations/proposePlatformPayoutAlertRoute) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Reject route authority without creating a delivery route. (/reports-api/endpoints/payout-operations/rejectPlatformPayoutAlertRouteProposal) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Make a recoverable ambiguity due for provider lookup after a distinct checker approves. (/reports-api/endpoints/payout-operations/requestPlatformPayoutLookupRecheck) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Retire a route with recent MFA and an actor distinct from its proposer. (/reports-api/endpoints/payout-operations/retirePlatformPayoutAlertRoute) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Return aggregate availability and freshness for published analytics generations. (/reports-api/endpoints/published-analytics/getPublishedAnalyticsReadiness) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Return exact totals from atomically published enterprise generations. (/reports-api/endpoints/published-analytics/getPublishedAnalyticsSummary) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Aggregate reviewed commercial dimensions across published generations. (/reports-api/endpoints/published-analytics/listPublishedAnalyticsBreakdown) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # List privacy-protected filter options across published commercial dimensions. (/reports-api/endpoints/published-analytics/listPublishedAnalyticsFilterOptions) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # List privacy-thresholded generation-scoped observed CPM or per-unit rates. (/reports-api/endpoints/published-analytics/listPublishedObservedRates) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Return exact complete-file canonical and validation evidence for one import. (/reports-api/endpoints/reconciliation/getPlatformReconciliation) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # List bounded completed canonical reconciliations with validation evidence. (/reports-api/endpoints/reconciliation/listPlatformReconciliations) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # Accept one bounded, signed and ordered partner event. (/reports-api/endpoints/webhook-ingress/acceptPlatformInboundWebhook) {/* Generated from api-reference\/reports-openapi.yaml. Run npm run generate:api to refresh. */} # SpaceMedia Delivery API OpenAPI contract Build organization-scoped music distribution integrations with the SpaceMedia Delivery API. Exchange an organization API key and secret at POST /api/v1/token, reuse the returned bearer token until shortly before expires_at, and send only stable public references such as user_id, artist_id, release_id, track_id, role_id, and checkout_id. Production and staging use separate credentials and data. Catalog ownership operations require a same-organization X-User-Id when stated by the operation. The contract covers catalog creation, audio and artwork upload, release readiness and review, delivery configuration, billing, add-ons, members, branding, smartlinks, copyright workflows, DDEX, and signed enterprise webhooks. DDEX and enterprise webhook routes are currently available in staging for onboarding and conformance; do not use them in production until SpaceMedia confirms production route and connection activation. Follow Retry-After on 429 responses, do not automatically retry high-impact mutations unless the operation supports Idempotency-Key, and verify resource state after an uncertain outcome. Numeric record references, system-only operations, dashboard routes, payment-provider secrets, and backend implementation details are not part of this public contract. Start with https://docs.spacemedia.uk/delivery-api/api-quickstart and use https://docs.spacemedia.uk/delivery-api/go-live-checklist before production cutover. Canonical source: https://docs.spacemedia.uk/delivery-api/openapi.json ## Authentication Exchange organization credentials for an opaque bearer token and inspect the authenticated API client context. ### GET /api/v1/me Operation: `getAuthenticatedApiContext` Get Authenticated API Context Validate the bearer token currently being used by the integration. The response confirms expiry, API client name, and organization name without returning storage identifiers or secret material. Security: ```json [ { "BearerAuth": [] } ] ``` #### Responses - **200**: Token is valid. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "data": { "type": "object", "additionalProperties": true, "properties": { "expires_at": { "type": "string", "format": "date-time", "example": "2026-07-04T11:30:00+00:00", "description": "Timestamp for when expires occurred, formatted as ISO 8601 when available." }, "client": { "type": "object", "additionalProperties": true, "properties": { "name": { "type": "string", "example": "Northstar Distribution API", "description": "Display name for this client." }, "organization_name": { "type": "string", "example": "Northstar Distribution", "description": "Display name of the organization that owns the record." }, "capabilities": { "type": "array", "items": { "type": "string" }, "example": [ "catalog:read" ], "description": "Effective domain capabilities granted to this API client." } }, "example": { "name": "Northstar Distribution API", "organization_name": "Northstar Distribution", "capabilities": [ "catalog:read" ] }, "description": "API client context associated with the bearer token." }, "organization": { "type": "object", "additionalProperties": true, "properties": { "name": { "type": "string", "example": "Northstar Distribution", "description": "Display name for this organization." } }, "example": { "name": "Northstar Distribution" }, "description": "Organization summary scoped to the authenticated API credential." } }, "example": { "expires_at": "2026-07-04T11:30:00+00:00", "client": { "name": "Northstar Distribution API", "organization_name": "Northstar Distribution", "capabilities": [ "catalog:read" ] }, "organization": { "name": "Northstar Distribution" } }, "description": "Primary response payload for this request." } }, "example": { "success": true, "data": { "expires_at": "2026-07-04T11:30:00+00:00", "client": { "name": "Northstar Distribution API", "organization_name": "Northstar Distribution" }, "organization": { "name": "Northstar Distribution" } } }, "required": [ "success", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### POST /api/v1/token Operation: `createApiToken` Create API Token Exchange organization API credentials for a bearer token. Store the returned access_token securely, send it in the Authorization header, and refresh it before expires_at instead of retrying failed protected calls. Security: ```json [] ``` #### Parameters - `X-Api-Key` in header (string, required): Organization API key. - `X-Api-Secret` in header (string, required): Organization API secret. Never expose this in browser code. #### Responses - **200**: Access token created. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "data": { "type": "object", "additionalProperties": true, "properties": { "access_token": { "type": "string", "example": "0000000000000000000000000000000000000000963fbb8e", "description": "Bearer token used to authenticate protected Enterprise API requests." }, "token_type": { "type": "string", "example": "Bearer", "description": "Authentication scheme to use with the returned access token." }, "expires_at": { "type": "string", "format": "date-time", "example": "2026-07-04T11:30:00+00:00", "description": "Timestamp for when expires occurred, formatted as ISO 8601 when available." } }, "example": { "access_token": "0000000000000000000000000000000000000000963fbb8e", "token_type": "Bearer", "expires_at": "2026-07-04T11:30:00+00:00" }, "description": "Primary response payload for this request." } }, "example": { "success": true, "data": { "access_token": "0000000000000000000000000000000000000000963fbb8e", "token_type": "Bearer", "expires_at": "2026-07-04T11:30:00+00:00" } }, "required": [ "success", "data" ] } ``` - **401**: Invalid API credentials. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ## WordPress OAuth Register a verified WordPress installation, authorize read-only catalog access with PKCE, rotate short-lived tokens, synchronize releases, and revoke the connection. ### POST /api/v1/integrations/wordpress/oauth/register Operation: `registerWordPressOAuthInstallation` Register a WordPress Installation Register a WordPress installation after SpaceMedia verifies a one-time challenge on the same public HTTPS host. Registration returns a public client identifier and never requires or returns a client secret. Security: ```json [] ``` #### Request body Required. **application/json** ```json { "type": "object", "required": [ "site_url", "redirect_uri", "challenge", "challenge_url" ], "properties": { "site_url": { "type": "string", "format": "uri", "description": "Canonical public HTTPS URL of the WordPress site." }, "redirect_uri": { "type": "string", "format": "uri", "description": "Plugin callback URL on the same host as site_url." }, "challenge": { "type": "string", "minLength": 64, "maxLength": 64, "description": "One-time verification value exposed by challenge_url." }, "challenge_url": { "type": "string", "format": "uri", "description": "Public plugin verification endpoint on the same host." }, "plugin_version": { "type": [ "string", "null" ], "maxLength": 30 } } } ``` #### Responses - **201**: The verified installation was registered and its OAuth endpoint metadata was returned. **application/json** ```json { "type": "object", "required": [ "client_id", "authorization_endpoint", "token_endpoint", "catalog_endpoint", "revoke_endpoint" ], "properties": { "client_id": { "type": "string" }, "authorization_endpoint": { "type": "string", "format": "uri" }, "token_endpoint": { "type": "string", "format": "uri" }, "catalog_endpoint": { "type": "string", "format": "uri" }, "revoke_endpoint": { "type": "string", "format": "uri" } } } ``` - **422**: Response - **429**: Response - **500**: Response ### GET /api/v1/integrations/wordpress/oauth/authorize Operation: `showWordPressOAuthAuthorization` Review WordPress Catalog Access Open the authenticated SpaceMedia consent screen for a registered WordPress installation. The request requires an active browser session and uses OAuth state plus PKCE S256 to bind the callback securely. Security: ```json [] ``` #### Parameters - `response_type` in query (string, required) - `client_id` in query (string, required) - `redirect_uri` in query (string, required) - `scope` in query (string, required) - `state` in query (string, required) - `code_challenge` in query (string, required) - `code_challenge_method` in query (string, required) #### Responses - **200**: Authenticated HTML consent screen for the registered installation. **text/html** ```json { "type": "string" } ``` - **422**: Response - **429**: Response - **500**: Response ### POST /api/v1/integrations/wordpress/oauth/authorize Operation: `decideWordPressOAuthAuthorization` Approve or Deny WordPress Catalog Access Approve or deny the pending read-only catalog request in an authenticated SpaceMedia browser session. Approval creates a single-use authorization code that expires after ten minutes and is returned only to the registered callback. Security: ```json [] ``` #### Request body Required. **application/x-www-form-urlencoded** ```json { "type": "object", "required": [ "response_type", "client_id", "redirect_uri", "scope", "state", "code_challenge", "code_challenge_method", "decision" ], "properties": { "response_type": { "type": "string", "const": "code" }, "client_id": { "type": "string" }, "redirect_uri": { "type": "string", "format": "uri" }, "scope": { "type": "string", "const": "catalog.read" }, "state": { "type": "string" }, "code_challenge": { "type": "string" }, "code_challenge_method": { "type": "string", "const": "S256" }, "decision": { "type": "string", "enum": [ "approve", "deny" ] } } } ``` #### Responses - **302**: Redirect to the registered callback with code and state, or with access_denied and state. - **422**: Response - **429**: Response - **500**: Response ### POST /api/v1/integrations/wordpress/oauth/token Operation: `exchangeWordPressOAuthToken` Exchange or Refresh a WordPress OAuth Token Exchange a single-use authorization code and PKCE verifier, or rotate a valid refresh token. Access tokens expire after fifteen minutes, refresh tokens rotate on every use, and token responses must never be cached or logged. Security: ```json [] ``` #### Request body Required. **application/json** ```json { "oneOf": [ { "type": "object", "required": [ "grant_type", "client_id", "code", "code_verifier", "redirect_uri" ], "properties": { "grant_type": { "type": "string", "const": "authorization_code" }, "client_id": { "type": "string" }, "code": { "type": "string" }, "code_verifier": { "type": "string", "minLength": 43, "maxLength": 128 }, "redirect_uri": { "type": "string", "format": "uri" } } }, { "type": "object", "required": [ "grant_type", "client_id", "refresh_token" ], "properties": { "grant_type": { "type": "string", "const": "refresh_token" }, "client_id": { "type": "string" }, "refresh_token": { "type": "string" } } } ] } ``` #### Responses - **200**: A new access token and rotating refresh token were issued with no-store caching. **application/json** ```json { "type": "object", "required": [ "token_type", "access_token", "expires_in", "refresh_token", "scope", "account_label" ], "properties": { "token_type": { "type": "string", "const": "Bearer" }, "access_token": { "type": "string" }, "expires_in": { "type": "integer", "const": 900 }, "refresh_token": { "type": "string" }, "scope": { "type": "string", "const": "catalog.read" }, "account_label": { "type": "string" } } } ``` - **400**: The grant type, authorization code, PKCE verifier, or refresh token is invalid. - **429**: Response - **500**: Response ### GET /api/v1/integrations/wordpress/oauth/catalog Operation: `getWordPressOAuthCatalog` Read the Authorized WordPress Catalog Return the authorized organization or user catalog as bounded release pages for the WordPress plugin. The endpoint is read-only, exposes public catalog references, and accepts only a short-lived WordPress OAuth bearer token. Security: ```json [ { "WordPressOAuthBearer": [] } ] ``` #### Parameters - `page` in query (integer) - `per_page` in query (integer) #### Responses - **200**: A bounded page of authorized releases and tracks was returned. **application/json** ```json { "type": "object", "required": [ "releases", "page", "has_more", "total" ], "properties": { "releases": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "page": { "type": "integer" }, "has_more": { "type": "boolean" }, "total": { "type": "integer" } } } ``` - **401**: Response - **429**: Response - **500**: Response ### POST /api/v1/integrations/wordpress/oauth/revoke Operation: `revokeWordPressOAuthConnection` Revoke WordPress Catalog Access Revoke the current WordPress installation connection and invalidate its access and refresh tokens. The operation is scoped by the presented short-lived WordPress OAuth bearer token and returns no secret material. Security: ```json [ { "WordPressOAuthBearer": [] } ] ``` #### Responses - **200**: The WordPress OAuth connection and its tokens were revoked. **application/json** ```json { "type": "object", "required": [ "revoked" ], "properties": { "revoked": { "type": "boolean", "const": true } } } ``` - **401**: Response - **429**: Response - **500**: Response ## Account Settings Read and update organization-visible account settings, sessions, notification preferences, personal information, and labels. ### POST /api/v1/account-settings/labels Operation: `createAccountLabel` Create Account Label Create Account Label. Use it to manage the authenticated user profile, account labels, active sessions, and notification preferences that are visible inside the organization account. It applies the requested change and returns the updated resource, validation result, or action status needed for the next API step. Security: ```json [ { "BearerAuth": [] } ] ``` #### Request body Request payload. Required. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "name": { "type": "string", "example": "Night Shift Records", "description": "Display name for this request body." } }, "required": [ "name" ] } ``` #### Responses - **200**: Create Account Label succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "Label created.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." }, "data": { "type": "object", "additionalProperties": true, "properties": { "label_id": { "type": "string", "example": "7da47646-3011-43f8-b497-8a5b1bc2d546", "format": "uuid", "description": "Stable public label reference. Use this value in related endpoint paths and request bodies." }, "name": { "type": "string", "example": "Night Shift Records", "description": "Display name for this data." }, "releases_count": { "type": "integer", "example": 18, "description": "Number of releases currently associated with the artist." }, "created_at": { "type": "string", "example": "2026-07-04T09:30:00+00:00", "format": "date-time", "description": "Timestamp for when created occurred, formatted as ISO 8601 when available." } }, "description": "Primary response payload for this request." } }, "required": [ "success", "message", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **422**: Validation failed for name. The request was not applied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### GET /api/v1/account-settings/me Operation: `getCurrentAccountSettings` View Current Account Settings View Current Account Settings. Use it to manage the authenticated user profile, account labels, active sessions, and notification preferences that are visible inside the organization account. It returns public references and organization-visible fields only, so clients can safely use returned values in follow-up API calls. Security: ```json [ { "BearerAuth": [] } ] ``` #### Responses - **200**: View Current Account Settings succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "data": { "type": "object", "additionalProperties": true, "properties": { "profile": { "type": "object", "additionalProperties": true, "properties": { "user_id": { "type": "string", "example": "7d2d9f72-c0a2-4d4b-9b6d-7caa942b8a71", "format": "uuid", "description": "Stable public user reference. Use this value in related endpoint paths and request bodies." }, "name": { "type": "string", "example": "Maya Chen", "description": "Display name for this profile." }, "full_name": { "type": "string", "example": "Maya Chen", "description": "Full display name assembled from the account profile fields." }, "first_name": { "type": "string", "example": "Maya", "description": "Given name for the user or member profile." }, "last_name": { "type": "string", "example": "Chen", "description": "Family name for the user or member profile." }, "email": { "type": "string", "example": "maya.chen@northstar-distribution.co.uk", "description": "Email address associated with the account, member, invitation, or beneficiary." }, "phone": { "type": "string", "example": "+442071838750", "description": "Phone number on the account profile when provided." }, "language": { "type": "string", "example": "en", "description": "Primary language value used for profile, release, or track metadata." }, "country": { "type": "string", "example": "United Kingdom", "description": "Country associated with the user, artist, or organization record." }, "profile_photo": { "type": "string", "example": "https://assets.spacemedia-docs.invalid/users/maya-chen/profile-photo.webp", "format": "uri", "description": "Public media URL or asset reference for the uploaded image." }, "verified": { "type": "boolean", "example": true, "description": "Whether the account email or identity state is verified." }, "email_verified_at": { "type": "string", "example": "2026-06-25T08:15:00+00:00", "format": "date-time", "description": "Timestamp for when email verified occurred, formatted as ISO 8601 when available." }, "last_login_at": { "type": "string", "example": "2026-07-04T10:15:00+00:00", "format": "date-time", "description": "Timestamp for when last login occurred, formatted as ISO 8601 when available." }, "invitation_status": { "type": "string", "example": "accepted", "description": "Invitation lifecycle status, such as pending or accepted." }, "is_invited": { "type": "boolean", "example": false, "description": "Whether this user was created through an organization invitation." }, "is_suspended": { "type": "boolean", "example": false, "description": "Whether organization access is currently suspended for this account." }, "roles": { "type": "array", "items": { "type": "object", "additionalProperties": true, "properties": { "role_id": { "type": "string", "example": "c0f1c68c-7c2f-4954-b52c-9d7e5eb46d3e", "format": "uuid", "description": "Stable public role reference. Use this value in related endpoint paths and request bodies." }, "name": { "type": "string", "example": "Catalog Manager", "description": "Display name for this roles." } } }, "description": "Roles assigned to the user or member within the organization." }, "organization_name": { "type": "string", "example": "Northstar Distribution", "description": "Display name of the organization that owns the record." }, "created_at": { "type": "string", "example": "2026-07-04T09:30:00+00:00", "format": "date-time", "description": "Timestamp for when created occurred, formatted as ISO 8601 when available." }, "updated_at": { "type": "string", "example": "2026-07-04T10:15:00+00:00", "format": "date-time", "description": "Timestamp for when updated occurred, formatted as ISO 8601 when available." } }, "description": "Profile object for the account, theme, email theme, or member being returned." }, "labels": { "type": "array", "items": { "type": "object", "additionalProperties": true, "properties": { "label_id": { "type": "string", "example": "7da47646-3011-43f8-b497-8a5b1bc2d546", "format": "uuid", "description": "Stable public label reference. Use this value in related endpoint paths and request bodies." }, "name": { "type": "string", "example": "Night Shift Records", "description": "Display name for this labels." }, "releases_count": { "type": "integer", "example": 18, "description": "Number of releases currently associated with the artist." }, "created_at": { "type": "string", "example": "2026-07-04T09:30:00+00:00", "format": "date-time", "description": "Timestamp for when created occurred, formatted as ISO 8601 when available." } } }, "description": "Custom labels available to the authenticated account or organization." }, "artist_types": { "type": "array", "items": { "type": "string", "example": "Primary Artist" }, "description": "Artist type options available for catalog metadata forms." }, "genres": { "type": "array", "items": { "type": "string", "example": "Electronic" }, "description": "Genre options available for release and track metadata forms." }, "languages": { "type": "array", "items": { "type": "string", "example": "English" }, "description": "Language options available for release and track metadata forms." }, "notification_preferences": { "type": "object", "additionalProperties": true, "properties": { "release_status": { "type": "boolean", "example": true, "description": "Current release status shown to the organization." }, "payment_updates": { "type": "boolean", "example": true, "description": "Whether the user receives payment, invoice, checkout, and billing status notifications." }, "product_updates": { "type": "boolean", "example": false, "description": "Whether the user receives product, add-on, and feature update notifications." } }, "description": "Notification settings currently stored for the authenticated account." } }, "description": "Primary response payload for this request." } }, "required": [ "success", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### POST /api/v1/account-settings/notifications Operation: `updateNotificationPreferences` Update Notification Preferences Update Notification Preferences. Use it to manage the authenticated user profile, account labels, active sessions, and notification preferences that are visible inside the organization account. It applies the requested change and returns the updated resource, validation result, or action status needed for the next API step. Security: ```json [ { "BearerAuth": [] } ] ``` #### Request body Request payload. Required. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "release_status": { "type": "boolean", "example": true, "description": "Current release status shown to the organization." }, "payment_updates": { "type": "boolean", "example": true, "description": "Whether the user receives payment, invoice, checkout, and billing status notifications." }, "product_updates": { "type": "boolean", "example": false, "description": "Whether the user receives product, add-on, and feature update notifications." } }, "minProperties": 1, "description": "Send at least one notification preference to update." } ``` #### Responses - **200**: Update Notification Preferences succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "Notification preferences updated.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." } }, "required": [ "success", "message" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **422**: Validation failed for release_status. The request was not applied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### POST /api/v1/account-settings/personal-information Operation: `updatePersonalInformation` Update Personal Information Update Personal Information. Use it to manage the authenticated user profile, account labels, active sessions, and notification preferences that are visible inside the organization account. It applies the requested change and returns the updated resource, validation result, or action status needed for the next API step. Security: ```json [ { "BearerAuth": [] } ] ``` #### Request body Request payload. Required. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "first_name": { "type": "string", "example": "Maya", "description": "Given name for the user or member profile." }, "last_name": { "type": "string", "example": "Chen", "description": "Family name for the user or member profile." }, "phone": { "type": "string", "example": "+442071838750", "description": "Phone number on the account profile when provided." }, "country": { "type": "string", "example": "United Kingdom", "description": "Country associated with the user, artist, or organization record." }, "language": { "type": "string", "example": "en", "description": "Primary language value used for profile, release, or track metadata." } }, "required": [ "first_name", "last_name" ] } ``` #### Responses - **200**: Update Personal Information succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "Personal information updated successfully.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." } }, "required": [ "success", "message" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **422**: Validation failed for first_name. The request was not applied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### GET /api/v1/account-settings/sessions Operation: `listAccountSessions` List Account Sessions List Account Sessions. Use it to manage the authenticated user profile, account labels, active sessions, and notification preferences that are visible inside the organization account. It returns public references and organization-visible fields only, so clients can safely use returned values in follow-up API calls. Security: ```json [ { "BearerAuth": [] } ] ``` #### Responses - **200**: List Account Sessions succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "data": { "type": "array", "items": { "type": "object", "additionalProperties": true, "properties": { "session_id": { "type": "string", "example": "6c53fe6af9bb6ec0487d27d0a0238edb7ad3ad9ad0e7a849a474efc53ea13f71", "description": "Opaque session revocation reference returned by the session list. Use it only with the delete-session endpoint and do not parse it for user, device, or storage details.", "pattern": "^[a-f0-9]{64}$", "minLength": 64, "maxLength": 64 }, "device": { "type": "string", "example": "Chrome on macOS", "description": "Browser, device, or client name associated with an active session." }, "ip": { "type": "string", "example": "203.0.113.10", "description": "IP address associated with an active session when available to the account." }, "last_active_at": { "type": "string", "example": "2026-07-04T10:15:00+00:00", "format": "date-time", "description": "Timestamp for when last active occurred, formatted as ISO 8601 when available." }, "current": { "type": "boolean", "example": true, "description": "Whether the session or setting refers to the current authenticated request." } } }, "description": "Primary response payload for this request." }, "meta": { "type": "object", "additionalProperties": true, "properties": { "current_page": { "type": "integer", "example": 1, "description": "current page for meta." }, "last_page": { "type": "integer", "example": 1, "description": "last page for meta." }, "per_page": { "type": "integer", "example": 20, "description": "per page for meta." }, "total": { "type": "integer", "example": 1, "description": "Total number of records matching the current filters." }, "from": { "type": "integer", "example": 1, "description": "from for meta." }, "to": { "type": "integer", "example": 1, "description": "to for meta." } }, "description": "Pagination, filter, or response metadata for this request." } }, "required": [ "success", "data", "meta" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### DELETE /api/v1/account-settings/sessions/{session_id} Operation: `deleteAccountSession` Delete Account Session Delete Account Session. Use it to manage the authenticated user profile, account labels, active sessions, and notification preferences that are visible inside the organization account. It removes, revokes, or cancels the target when permissions and resource state allow it, then returns a confirmation or policy error. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `session_id` in path (string, required): Opaque session revocation reference returned by GET /api/v1/account-settings/sessions. #### Responses - **200**: Delete Account Session succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "Session deleted.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." } }, "required": [ "success", "message" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **404**: Resource not found. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### GET /api/v1/labels Operation: `listLabels` List Labels List Labels. Use it to manage the authenticated user profile, account labels, active sessions, and notification preferences that are visible inside the organization account. It returns public references and organization-visible fields only, so clients can safely use returned values in follow-up API calls. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `search` in query (string): Search term for matching visible records. - `page` in query (integer): Page number to return. - `size` in query (integer): Number of records per page. - `sort` in query (string): Sort direction for creation date. #### Responses - **200**: List Labels succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "data": { "type": "array", "items": { "type": "object", "additionalProperties": true, "properties": { "label_id": { "type": "string", "example": "7da47646-3011-43f8-b497-8a5b1bc2d546", "format": "uuid", "description": "Stable public label reference. Use this value in related endpoint paths and request bodies." }, "name": { "type": "string", "example": "Night Shift Records", "description": "Display name for this data." }, "releases_count": { "type": "integer", "example": 18, "description": "Number of releases currently associated with the artist." }, "created_at": { "type": "string", "example": "2026-07-04T09:30:00+00:00", "format": "date-time", "description": "Timestamp for when created occurred, formatted as ISO 8601 when available." } } }, "description": "Primary response payload for this request." }, "meta": { "type": "object", "additionalProperties": true, "properties": { "current_page": { "type": "integer", "example": 1, "description": "current page for meta." }, "last_page": { "type": "integer", "example": 1, "description": "last page for meta." }, "per_page": { "type": "integer", "example": 20, "description": "per page for meta." }, "total": { "type": "integer", "example": 1, "description": "Total number of records matching the current filters." }, "from": { "type": "integer", "example": 1, "description": "from for meta." }, "to": { "type": "integer", "example": 1, "description": "to for meta." } }, "description": "Pagination, filter, or response metadata for this request." } }, "required": [ "success", "data", "meta" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **422**: Validation failed for search. The request was not applied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### POST /api/v1/labels Operation: `createLabel` Create Label Create Label. Use it to manage the authenticated user profile, account labels, active sessions, and notification preferences that are visible inside the organization account. It applies the requested change and returns the updated resource, validation result, or action status needed for the next API step. Security: ```json [ { "BearerAuth": [] } ] ``` #### Request body Request payload. Required. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "name": { "type": "string", "example": "Aurora Tape Club", "description": "Display name for this request body." } }, "required": [ "name" ] } ``` #### Responses - **200**: Create Label succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "Label created.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." }, "data": { "type": "object", "additionalProperties": true, "properties": { "label_id": { "type": "string", "example": "45ac6d34-9374-4fa6-a6fc-08bd49183a12", "format": "uuid", "description": "Stable public label reference. Use this value in related endpoint paths and request bodies." }, "name": { "type": "string", "example": "Aurora Tape Club", "description": "Display name for this data." }, "releases_count": { "type": "integer", "example": 18, "description": "Number of releases currently associated with the artist." }, "created_at": { "type": "string", "example": "2026-07-04T09:30:00+00:00", "format": "date-time", "description": "Timestamp for when created occurred, formatted as ISO 8601 when available." } }, "description": "Primary response payload for this request." } }, "required": [ "success", "message", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **422**: Validation failed for name. The request was not applied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### GET /api/v1/labels/{label_id} Operation: `getLabel` View Label View Label. Use it to manage the authenticated user profile, account labels, active sessions, and notification preferences that are visible inside the organization account. It returns public references and organization-visible fields only, so clients can safely use returned values in follow-up API calls. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `label_id` in path (string, required): Public label reference returned by the API. #### Responses - **200**: View Label succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "data": { "type": "object", "additionalProperties": true, "properties": { "label_id": { "type": "string", "example": "7da47646-3011-43f8-b497-8a5b1bc2d546", "format": "uuid", "description": "Stable public label reference. Use this value in related endpoint paths and request bodies." }, "name": { "type": "string", "example": "Night Shift Records", "description": "Display name for this data." }, "releases_count": { "type": "integer", "example": 18, "description": "Number of releases currently associated with the artist." }, "created_at": { "type": "string", "example": "2026-07-04T09:30:00+00:00", "format": "date-time", "description": "Timestamp for when created occurred, formatted as ISO 8601 when available." } }, "description": "Primary response payload for this request." } }, "required": [ "success", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **404**: Resource not found. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ## Reference Data Discover public country, territory, and distribution-channel values instead of hardcoding dashboard labels. ### GET /api/v1/countries Operation: `listCountries` List Countries List Countries. Use it to fetch stable country, territory, language, and catalog option values before building release, rights, billing, or profile forms. It returns public references and organization-visible fields only, so clients can safely use returned values in follow-up API calls. Security: ```json [ { "BearerAuth": [] } ] ``` #### Responses - **200**: List Countries succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "data": { "type": "array", "items": { "type": "object", "additionalProperties": true, "properties": { "code": { "type": "string", "example": "GB", "description": "Stable public code for a country, territory, permission, package, or status option." }, "name": { "type": "string", "example": "United Kingdom", "description": "Display name for this data." }, "phone_code": { "type": "string", "example": "+44", "description": "PHONE CODE code used for catalog, country, currency, or rights metadata." } } }, "description": "Primary response payload for this request." } }, "required": [ "success", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### GET /api/v1/releases/distribution-channels Operation: `listReleaseDistributionChannels` List Distribution Channels List the enabled distribution channels that can be selected for release delivery. Use the stable channel codes in release distribution requests while presenting the public names in client interfaces. Security: ```json [ { "BearerAuth": [] } ] ``` #### Responses - **200**: Enabled release distribution channels returned successfully. **application/json** ```json { "type": "object", "additionalProperties": false, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "data": { "type": "array", "items": { "type": "object", "additionalProperties": false, "properties": { "code": { "type": "string", "example": "spotify", "description": "Stable delivery-channel code accepted by release distribution requests." }, "name": { "type": "string", "example": "Spotify", "description": "Public display name for the delivery channel." } }, "required": [ "code", "name" ] }, "description": "Enabled delivery channels available to the authenticated organization." } }, "required": [ "success", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### GET /api/v1/releases/territories Operation: `listReleaseTerritories` List Release Territories List Release Territories. Use it to fetch stable country, territory, language, and catalog option values before building release, rights, billing, or profile forms. It returns public references and organization-visible fields only, so clients can safely use returned values in follow-up API calls. Security: ```json [ { "BearerAuth": [] } ] ``` #### Responses - **200**: List Release Territories succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "data": { "type": "array", "items": { "type": "object", "additionalProperties": true, "properties": { "code": { "type": "string", "example": "WORLDWIDE", "description": "Stable public code for a country, territory, permission, package, or status option." }, "name": { "type": "string", "example": "Worldwide", "description": "Display name for this data." } } }, "description": "Primary response payload for this request." } }, "required": [ "success", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ## Artists Create and maintain artist profiles used by releases, tracks, credits, and catalog search. ### GET /api/v1/artists Operation: `listArtists` List Artists List Artists. Use it to create and maintain artist profiles that can be attached to releases, tracks, primary artist credits, featured artist credits, and catalog searches. It returns public references and organization-visible fields only, so clients can safely use returned values in follow-up API calls. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `search` in query (string): Search term for matching visible records. - `page` in query (integer): Page number to return. - `size` in query (integer): Number of records per page. - `sort` in query (string): Sort direction for creation date. - `X-User-Id` in header (string): Optional user_id to perform an allowed action for a user in the same organization. #### Responses - **200**: List Artists succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "data": { "type": "array", "items": { "type": "object", "additionalProperties": true, "properties": { "artist_id": { "type": "string", "example": "6f209ac7-d82c-4c8f-9d3e-bfe39c0df802", "format": "uuid", "description": "Stable public artist reference. Use this value in related endpoint paths and request bodies." }, "name": { "type": "string", "example": "Nova Vale", "description": "Display name for this data." }, "artist_type": { "type": "string", "example": "Primary Artist", "description": "Artist classification used for DSP metadata and credit display." }, "spotify_id": { "type": "string", "example": "3mY7kJqR8B2nQvP6LxT4Za", "description": "Optional external Spotify artist reference for matching catalog profiles. It is not a SpaceMedia API path reference; use artist_id for SpaceMedia API calls." }, "bio": { "type": "string", "example": "Electronic artist and producer from London.", "description": "Artist biography or descriptive profile text." }, "country": { "type": "string", "example": "GB", "description": "Country associated with the user, artist, or organization record." }, "releases_count": { "type": "integer", "example": 2, "description": "Number of releases currently associated with the artist." }, "tracks_count": { "type": "integer", "example": 7, "description": "Number of tracks currently associated with the artist." }, "total_streams": { "type": "integer", "example": 125000, "description": "Total reported streams when reporting data is available." }, "created_at": { "type": "string", "example": "2026-06-01T11:00:00+00:00", "format": "date-time", "description": "Timestamp for when created occurred, formatted as ISO 8601 when available." }, "updated_at": { "type": "string", "example": "2026-07-04T10:15:00+00:00", "format": "date-time", "description": "Timestamp for when updated occurred, formatted as ISO 8601 when available." } } }, "description": "Primary response payload for this request." }, "meta": { "type": "object", "additionalProperties": true, "properties": { "current_page": { "type": "integer", "example": 1, "description": "current page for meta." }, "last_page": { "type": "integer", "example": 1, "description": "last page for meta." }, "per_page": { "type": "integer", "example": 20, "description": "per page for meta." }, "total": { "type": "integer", "example": 1, "description": "Total number of records matching the current filters." }, "from": { "type": "integer", "example": 1, "description": "from for meta." }, "to": { "type": "integer", "example": 1, "description": "to for meta." } }, "description": "Pagination, filter, or response metadata for this request." } }, "required": [ "success", "data", "meta" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **422**: Validation failed for search. The request was not applied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### POST /api/v1/artists Operation: `createArtist` Create Artist Create Artist. Use it to create and maintain artist profiles that can be attached to releases, tracks, primary artist credits, featured artist credits, and catalog searches. It applies the requested change and returns the updated resource, validation result, or action status needed for the next API step. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `X-User-Id` in header (string, required): Required user_id for catalog ownership and quota context. The client must also have users:act-as. #### Request body Request payload. Required. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "name": { "type": "string", "example": "Nova Vale", "description": "Display name for this request body." }, "bio": { "type": "string", "example": "Electronic artist and producer from London.", "description": "Artist biography or descriptive profile text." }, "spotify_id": { "type": "string", "example": "3mY7kJqR8B2nQvP6LxT4Za", "description": "Optional external Spotify artist reference for matching catalog profiles. It is not a SpaceMedia API path reference; use artist_id for SpaceMedia API calls." }, "country": { "type": "string", "example": "GB", "description": "Country associated with the user, artist, or organization record." } }, "required": [ "name" ] } ``` #### Responses - **200**: Create Artist succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "Artist created.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." }, "data": { "type": "object", "additionalProperties": true, "properties": { "artist_id": { "type": "string", "example": "6f209ac7-d82c-4c8f-9d3e-bfe39c0df802", "format": "uuid", "description": "Stable public artist reference. Use this value in related endpoint paths and request bodies." }, "name": { "type": "string", "example": "Nova Vale", "description": "Display name for this data." }, "artist_type": { "type": "string", "example": "Primary Artist", "description": "Artist classification used for DSP metadata and credit display." }, "spotify_id": { "type": "string", "example": "3mY7kJqR8B2nQvP6LxT4Za", "description": "Optional external Spotify artist reference for matching catalog profiles. It is not a SpaceMedia API path reference; use artist_id for SpaceMedia API calls." }, "bio": { "type": "string", "example": "Electronic artist and producer from London.", "description": "Artist biography or descriptive profile text." }, "country": { "type": "string", "example": "GB", "description": "Country associated with the user, artist, or organization record." }, "releases_count": { "type": "integer", "example": 2, "description": "Number of releases currently associated with the artist." }, "tracks_count": { "type": "integer", "example": 7, "description": "Number of tracks currently associated with the artist." }, "total_streams": { "type": "integer", "example": 125000, "description": "Total reported streams when reporting data is available." }, "created_at": { "type": "string", "example": "2026-06-01T11:00:00+00:00", "format": "date-time", "description": "Timestamp for when created occurred, formatted as ISO 8601 when available." }, "updated_at": { "type": "string", "example": "2026-07-04T10:15:00+00:00", "format": "date-time", "description": "Timestamp for when updated occurred, formatted as ISO 8601 when available." } }, "description": "Primary response payload for this request." } }, "required": [ "success", "message", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **422**: Validation failed for name. The request was not applied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### POST /api/v1/artists/{artist_id} Operation: `updateArtist` Update Artist Update Artist. Use it to create and maintain artist profiles that can be attached to releases, tracks, primary artist credits, featured artist credits, and catalog searches. It applies the requested change and returns the updated resource, validation result, or action status needed for the next API step. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `artist_id` in path (string, required): Public artist reference returned by the API. - `X-User-Id` in header (string, required): Required user_id for catalog ownership and quota context. The client must also have users:act-as. #### Request body Request payload. Required. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "name": { "type": "string", "example": "Nova Vale", "description": "Display name for this request body." }, "bio": { "type": "string", "example": "Electronic artist, vocalist, and producer from London.", "description": "Artist biography or descriptive profile text." }, "spotify_id": { "type": "string", "example": "3mY7kJqR8B2nQvP6LxT4Za", "description": "Optional external Spotify artist reference for matching catalog profiles. It is not a SpaceMedia API path reference; use artist_id for SpaceMedia API calls." } }, "required": [ "name" ] } ``` #### Responses - **200**: Update Artist succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "Artist updated.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." }, "data": { "type": "object", "additionalProperties": true, "properties": { "artist_id": { "type": "string", "example": "6f209ac7-d82c-4c8f-9d3e-bfe39c0df802", "format": "uuid", "description": "Stable public artist reference. Use this value in related endpoint paths and request bodies." }, "name": { "type": "string", "example": "Nova Vale", "description": "Display name for this data." }, "artist_type": { "type": "string", "example": "Primary Artist", "description": "Artist classification used for DSP metadata and credit display." }, "spotify_id": { "type": "string", "example": "3mY7kJqR8B2nQvP6LxT4Za", "description": "Optional external Spotify artist reference for matching catalog profiles. It is not a SpaceMedia API path reference; use artist_id for SpaceMedia API calls." }, "bio": { "type": "string", "example": "Electronic artist, vocalist, and producer from London.", "description": "Artist biography or descriptive profile text." }, "country": { "type": "string", "example": "GB", "description": "Country associated with the user, artist, or organization record." }, "releases_count": { "type": "integer", "example": 2, "description": "Number of releases currently associated with the artist." }, "tracks_count": { "type": "integer", "example": 7, "description": "Number of tracks currently associated with the artist." }, "total_streams": { "type": "integer", "example": 125000, "description": "Total reported streams when reporting data is available." }, "created_at": { "type": "string", "example": "2026-06-01T11:00:00+00:00", "format": "date-time", "description": "Timestamp for when created occurred, formatted as ISO 8601 when available." }, "updated_at": { "type": "string", "example": "2026-07-04T10:15:00+00:00", "format": "date-time", "description": "Timestamp for when updated occurred, formatted as ISO 8601 when available." } }, "description": "Primary response payload for this request." } }, "required": [ "success", "message", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **404**: Resource not found. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **422**: Validation failed for name. The request was not applied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### DELETE /api/v1/artists/{artist_id} Operation: `deleteArtist` Delete Artist Delete Artist. Use it to create and maintain artist profiles that can be attached to releases, tracks, primary artist credits, featured artist credits, and catalog searches. It removes, revokes, or cancels the target when permissions and resource state allow it, then returns a confirmation or policy error. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `artist_id` in path (string, required): Public artist reference returned by the API. #### Responses - **200**: Delete Artist succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "Artist deleted successfully.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." } }, "required": [ "success", "message" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **404**: Resource not found. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ## Releases Create releases, upload artwork, configure rights and destinations, check readiness, manage track order, and submit for review. ### POST /api/v1/pre-qc/legal-credit-name Operation: `validateLegalCreditName` Validate Legal Credit Name Validate a legal credit name and country before storing contributor or rights metadata on a release or track. Use it to catch formatting issues before submission. Security: ```json [ { "BearerAuth": [] } ] ``` #### Request body Request payload. Required. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "name": { "type": "string", "example": "Night Shift Records Ltd", "description": "Display name for this request body." }, "country": { "type": "string", "example": "GB", "description": "Country associated with the user, artist, or organization record." } }, "required": [ "name", "country" ] } ``` #### Responses - **200**: Validate Legal Credit Name succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "data": { "type": "object", "additionalProperties": true, "properties": { "valid": { "type": "boolean", "example": true, "description": "Whether the submitted value passed validation." }, "normalized_name": { "type": "string", "example": "Night Shift Records Ltd", "description": "Normalized legal credit name returned after validation." } }, "description": "Primary response payload for this request." } }, "required": [ "success", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **422**: Validation failed for name. The request was not applied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### GET /api/v1/releases Operation: `listReleases` List Releases List Releases. Use it to draft releases, update metadata, attach artwork and tracks, define rights, choose territories, and prepare releases for review and delivery. It returns public references and organization-visible fields only, so clients can safely use returned values in follow-up API calls. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `search` in query (string): Search term for matching visible records. - `page` in query (integer): Page number to return. - `size` in query (integer): Number of records per page. - `sort` in query (string): Sort direction for creation date. - `status` in query (string): Filter by release status. - `X-User-Id` in header (string): Optional user_id to perform an allowed action for a user in the same organization. #### Responses - **200**: List Releases succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "data": { "type": "array", "items": { "type": "object", "additionalProperties": true, "properties": { "release_id": { "type": "string", "example": "b7a15d95-58f6-4f67-b5d1-89f4f5bfb4d8", "format": "uuid", "description": "Stable public release reference. Use this value in related endpoint paths and request bodies." }, "title": { "type": "string", "example": "Midnight Atlas", "description": "Catalog or content title shown in the dashboard and API responses." }, "status": { "type": "string", "example": "draft", "description": "Current lifecycle status for this record." }, "format": { "type": "string", "example": "single", "description": "Release format, such as single, EP, or album." }, "label": { "type": "string", "example": "Night Shift Records", "description": "Label name attached to the release metadata." }, "genre": { "type": "string", "example": "Electronic", "description": "Primary release or track genre selected from supported values." }, "secondary_genre": { "type": "string", "example": "Ambient", "description": "Optional secondary genre used for more precise metadata." }, "language": { "type": "string", "example": "English", "description": "Primary language value used for profile, release, or track metadata." }, "explicit_content": { "type": "boolean", "example": false, "description": "Whether the release or track is marked as explicit." }, "upc_code": { "type": "string", "example": "5054429191012", "description": "UPC assigned to the release, or null when it has not been assigned yet." }, "reference_number": { "type": "string", "example": "NSD-2026-041", "description": "Human-readable catalog or billing reference shown in the dashboard." }, "scheduled_date": { "type": "string", "example": "2026-08-21", "format": "date", "description": "Scheduled release date used for delivery planning and catalog display." }, "original_release_date": { "type": "string", "example": "2026-08-21", "format": "date", "description": "Calendar date for original release." }, "copyright_detection_enabled": { "type": "boolean", "example": true, "description": "Whether copyright checking is enabled for the organization or release workflow." }, "price_category": { "type": "string", "example": "mid", "description": "Release price tier or commercial category used for store delivery and billing decisions." }, "territories": { "type": "array", "items": { "type": "string", "example": "GB" }, "description": "Territory codes where the release or rights metadata should apply." }, "distribution": { "type": "array", "items": { "type": "object", "additionalProperties": true, "properties": { "channel": { "type": "string", "example": "spotify", "description": "Delivery channel or store identifier using public snake_case values." }, "status": { "type": "string", "example": "selected", "description": "Current lifecycle status for this record." } } }, "description": "Delivery destinations and their organization-visible status values." }, "cover_art": { "type": "string", "example": "https://assets.spacemedia-docs.invalid/releases/midnight-atlas/cover.jpg", "format": "uri", "description": "Public media URL or asset reference for the uploaded image." }, "track_count": { "type": "integer", "example": 1, "description": "Number of track records visible in this context." }, "artists": { "type": "array", "items": { "type": "object", "additionalProperties": false, "properties": { "artist_id": { "type": "string", "example": "6f209ac7-d82c-4c8f-9d3e-bfe39c0df802", "format": "uuid", "description": "Public artist reference returned by the artists API." }, "name": { "type": "string", "example": "Nova Vale", "description": "Display name for this artists." }, "type": { "type": "string", "example": "Primary Artist", "description": "Artist credit role for this release or track, such as Primary Artist or Featured Artist." } }, "required": [ "artist_id", "type" ] }, "description": "Artists credited or attached to this catalog record." }, "created_by": { "type": "object", "additionalProperties": true, "properties": { "user_id": { "type": "string", "example": "7d2d9f72-c0a2-4d4b-9b6d-7caa942b8a71", "format": "uuid", "description": "Stable public user reference. Use this value in related endpoint paths and request bodies." }, "name": { "type": "string", "example": "Maya Chen", "description": "Display name for this created_by." }, "email": { "type": "string", "example": "maya.chen@northstar-distribution.co.uk", "description": "Email address associated with the account, member, invitation, or beneficiary." } }, "description": "User that created the record when available to the current organization." }, "created_at": { "type": "string", "example": "2026-07-04T09:30:00+00:00", "format": "date-time", "description": "Timestamp for when created occurred, formatted as ISO 8601 when available." }, "updated_at": { "type": "string", "example": "2026-07-04T10:15:00+00:00", "format": "date-time", "description": "Timestamp for when updated occurred, formatted as ISO 8601 when available." } } }, "description": "Primary response payload for this request." }, "meta": { "type": "object", "additionalProperties": true, "properties": { "current_page": { "type": "integer", "example": 1, "description": "current page for meta." }, "last_page": { "type": "integer", "example": 1, "description": "last page for meta." }, "per_page": { "type": "integer", "example": 20, "description": "per page for meta." }, "total": { "type": "integer", "example": 1, "description": "Total number of records matching the current filters." }, "from": { "type": "integer", "example": 1, "description": "from for meta." }, "to": { "type": "integer", "example": 1, "description": "to for meta." } }, "description": "Pagination, filter, or response metadata for this request." } }, "required": [ "success", "data", "meta" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **422**: Validation failed for search. The request was not applied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### POST /api/v1/releases Operation: `createRelease` Create Release Create Release. Use it to draft releases, update metadata, attach artwork and tracks, define rights, choose territories, and prepare releases for review and delivery. It applies the requested change and returns the updated resource, validation result, or action status needed for the next API step. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `X-User-Id` in header (string, required): Required user_id for catalog ownership and quota context. The client must also have users:act-as. #### Request body Multipart request payload. Required. **multipart/form-data** ```json { "type": "object", "additionalProperties": true, "properties": { "title": { "type": "string", "example": "Midnight Atlas", "description": "Catalog or content title shown in the dashboard and API responses." }, "cover_art": { "type": "string", "description": "Binary cover-art image file. Use JPG or PNG artwork that meets store artwork requirements.", "format": "binary" }, "label": { "type": "string", "example": "Night Shift Records", "description": "Label name attached to the release metadata." }, "copyright_material": { "type": "boolean", "example": false, "description": "Whether the submitter has indicated that copyright-sensitive material is present." }, "copyright_links": { "type": "array", "items": { "type": "string", "format": "uri", "example": "https://rights.northstar-distribution.co.uk/midnight-atlas-license.pdf", "description": "URL to a license, permission document, or rights note for declared copyrighted material." }, "description": "Supporting URLs for rights review when copyright material is declared." }, "upc": { "type": "string", "example": "5054429191012", "description": "UPC supplied for the release, or omitted when one should be assigned later." }, "reference": { "type": "string", "example": "NSD-2026-041", "description": "Human-readable catalog or billing reference shown in the dashboard." }, "remix_version": { "type": "string", "example": "", "description": "Version label such as Original Mix, Radio Edit, or Remix." }, "genre": { "type": "string", "example": "Electronic", "description": "Primary release or track genre selected from supported values." }, "secondary_genre": { "type": "string", "example": "Ambient", "description": "Optional secondary genre used for more precise metadata." }, "language": { "type": "string", "example": "English", "description": "Primary language value used for profile, release, or track metadata." }, "explicit_content": { "type": "boolean", "example": false, "description": "Whether the release or track is marked as explicit." }, "format": { "type": "string", "example": "single", "description": "Release format, such as single, EP, or album." }, "description": { "type": "string", "example": "A late-night electronic single built for DSP delivery.", "description": "Human-readable description for this record or workflow." }, "artists": { "type": "array", "items": { "type": "object", "additionalProperties": false, "properties": { "artist_id": { "type": "string", "example": "6f209ac7-d82c-4c8f-9d3e-bfe39c0df802", "format": "uuid", "description": "Public artist reference returned by the artists API." }, "type": { "type": "string", "example": "Primary Artist", "description": "Artist credit role for this release or track, such as Primary Artist or Featured Artist." } }, "required": [ "artist_id", "type" ] }, "description": "Artists credited or attached to this catalog record." } }, "required": [ "title", "cover_art", "format", "artists" ] } ``` #### Responses - **200**: Create Release succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "Release created.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." }, "data": { "type": "object", "additionalProperties": true, "properties": { "release_id": { "type": "string", "example": "b7a15d95-58f6-4f67-b5d1-89f4f5bfb4d8", "format": "uuid", "description": "Stable public release reference. Use this value in related endpoint paths and request bodies." }, "title": { "type": "string", "example": "Midnight Atlas", "description": "Catalog or content title shown in the dashboard and API responses." }, "status": { "type": "string", "example": "draft", "description": "Current lifecycle status for this record." }, "format": { "type": "string", "example": "single", "description": "Release format, such as single, EP, or album." }, "label": { "type": "string", "example": "Night Shift Records", "description": "Label name attached to the release metadata." }, "genre": { "type": "string", "example": "Electronic", "description": "Primary release or track genre selected from supported values." }, "secondary_genre": { "type": "string", "example": "Ambient", "description": "Optional secondary genre used for more precise metadata." }, "language": { "type": "string", "example": "English", "description": "Primary language value used for profile, release, or track metadata." }, "explicit_content": { "type": "boolean", "example": false, "description": "Whether the release or track is marked as explicit." }, "upc_code": { "type": "string", "example": "5054429191012", "description": "UPC assigned to the release, or null when it has not been assigned yet." }, "reference_number": { "type": "string", "example": "NSD-2026-041", "description": "Human-readable catalog or billing reference shown in the dashboard." }, "scheduled_date": { "type": "string", "example": "2026-08-21", "format": "date", "description": "Scheduled release date used for delivery planning and catalog display." }, "original_release_date": { "type": "string", "example": "2026-08-21", "format": "date", "description": "Calendar date for original release." }, "copyright_detection_enabled": { "type": "boolean", "example": true, "description": "Whether copyright checking is enabled for the organization or release workflow." }, "price_category": { "type": "string", "example": "mid", "description": "Release price tier or commercial category used for store delivery and billing decisions." }, "territories": { "type": "array", "items": { "type": "string", "example": "GB" }, "description": "Territory codes where the release or rights metadata should apply." }, "distribution": { "type": "array", "items": { "type": "object", "additionalProperties": true, "properties": { "channel": { "type": "string", "example": "spotify", "description": "Delivery channel or store identifier using public snake_case values." }, "status": { "type": "string", "example": "selected", "description": "Current lifecycle status for this record." } } }, "description": "Delivery destinations and their organization-visible status values." }, "cover_art": { "type": "string", "example": "https://assets.spacemedia-docs.invalid/releases/midnight-atlas/cover.jpg", "format": "uri", "description": "Public media URL or asset reference for the uploaded image." }, "track_count": { "type": "integer", "example": 0, "description": "Number of track records visible in this context." }, "artists": { "type": "array", "items": { "type": "object", "additionalProperties": false, "properties": { "artist_id": { "type": "string", "example": "6f209ac7-d82c-4c8f-9d3e-bfe39c0df802", "format": "uuid", "description": "Public artist reference returned by the artists API." }, "name": { "type": "string", "example": "Nova Vale", "description": "Display name for this artists." }, "type": { "type": "string", "example": "Primary Artist", "description": "Artist credit role for this release or track, such as Primary Artist or Featured Artist." } }, "required": [ "artist_id", "type" ] }, "description": "Artists credited or attached to this catalog record." }, "created_by": { "type": "object", "additionalProperties": true, "properties": { "user_id": { "type": "string", "example": "7d2d9f72-c0a2-4d4b-9b6d-7caa942b8a71", "format": "uuid", "description": "Stable public user reference. Use this value in related endpoint paths and request bodies." }, "name": { "type": "string", "example": "Maya Chen", "description": "Display name for this created_by." }, "email": { "type": "string", "example": "maya.chen@northstar-distribution.co.uk", "description": "Email address associated with the account, member, invitation, or beneficiary." } }, "description": "User that created the record when available to the current organization." }, "created_at": { "type": "string", "example": "2026-07-04T09:30:00+00:00", "format": "date-time", "description": "Timestamp for when created occurred, formatted as ISO 8601 when available." }, "updated_at": { "type": "string", "example": "2026-07-04T10:15:00+00:00", "format": "date-time", "description": "Timestamp for when updated occurred, formatted as ISO 8601 when available." } }, "description": "Primary response payload for this request." } }, "required": [ "success", "message", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **422**: Validation failed for artists.0.artist_id. The request was not applied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### GET /api/v1/releases/{release_id} Operation: `getRelease` View Release View Release. Use it to draft releases, update metadata, attach artwork and tracks, define rights, choose territories, and prepare releases for review and delivery. It returns public references and organization-visible fields only, so clients can safely use returned values in follow-up API calls. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `release_id` in path (string, required): Public release reference returned by the API. - `X-User-Id` in header (string): Optional user_id to perform an allowed action for a user in the same organization. #### Responses - **200**: View Release succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "data": { "type": "object", "additionalProperties": true, "properties": { "release_id": { "type": "string", "example": "b7a15d95-58f6-4f67-b5d1-89f4f5bfb4d8", "format": "uuid", "description": "Stable public release reference. Use this value in related endpoint paths and request bodies." }, "title": { "type": "string", "example": "Midnight Atlas", "description": "Catalog or content title shown in the dashboard and API responses." }, "status": { "type": "string", "example": "draft", "description": "Current lifecycle status for this record." }, "format": { "type": "string", "example": "single", "description": "Release format, such as single, EP, or album." }, "label": { "type": "string", "example": "Night Shift Records", "description": "Label name attached to the release metadata." }, "genre": { "type": "string", "example": "Electronic", "description": "Primary release or track genre selected from supported values." }, "secondary_genre": { "type": "string", "example": "Ambient", "description": "Optional secondary genre used for more precise metadata." }, "language": { "type": "string", "example": "English", "description": "Primary language value used for profile, release, or track metadata." }, "explicit_content": { "type": "boolean", "example": false, "description": "Whether the release or track is marked as explicit." }, "upc_code": { "type": "string", "example": "5054429191012", "description": "UPC assigned to the release, or null when it has not been assigned yet." }, "reference_number": { "type": "string", "example": "NSD-2026-041", "description": "Human-readable catalog or billing reference shown in the dashboard." }, "scheduled_date": { "type": "string", "example": "2026-08-21", "format": "date", "description": "Scheduled release date used for delivery planning and catalog display." }, "original_release_date": { "type": "string", "example": "2026-08-21", "format": "date", "description": "Calendar date for original release." }, "copyright_detection_enabled": { "type": "boolean", "example": true, "description": "Whether copyright checking is enabled for the organization or release workflow." }, "price_category": { "type": "string", "example": "mid", "description": "Release price tier or commercial category used for store delivery and billing decisions." }, "territories": { "type": "array", "items": { "type": "string", "example": "GB" }, "description": "Territory codes where the release or rights metadata should apply." }, "distribution": { "type": "array", "items": { "type": "object", "additionalProperties": true, "properties": { "channel": { "type": "string", "example": "spotify", "description": "Delivery channel or store identifier using public snake_case values." }, "status": { "type": "string", "example": "selected", "description": "Current lifecycle status for this record." } } }, "description": "Delivery destinations and their organization-visible status values." }, "cover_art": { "type": "string", "example": "https://assets.spacemedia-docs.invalid/releases/midnight-atlas/cover.jpg", "format": "uri", "description": "Public media URL or asset reference for the uploaded image." }, "track_count": { "type": "integer", "example": 1, "description": "Number of track records visible in this context." }, "artists": { "type": "array", "items": { "type": "object", "additionalProperties": false, "properties": { "artist_id": { "type": "string", "example": "6f209ac7-d82c-4c8f-9d3e-bfe39c0df802", "format": "uuid", "description": "Public artist reference returned by the artists API." }, "name": { "type": "string", "example": "Nova Vale", "description": "Display name for this artists." }, "type": { "type": "string", "example": "Primary Artist", "description": "Artist credit role for this release or track, such as Primary Artist or Featured Artist." } }, "required": [ "artist_id", "type" ] }, "description": "Artists credited or attached to this catalog record." }, "created_by": { "type": "object", "additionalProperties": true, "properties": { "user_id": { "type": "string", "example": "7d2d9f72-c0a2-4d4b-9b6d-7caa942b8a71", "format": "uuid", "description": "Stable public user reference. Use this value in related endpoint paths and request bodies." }, "name": { "type": "string", "example": "Maya Chen", "description": "Display name for this created_by." }, "email": { "type": "string", "example": "maya.chen@northstar-distribution.co.uk", "description": "Email address associated with the account, member, invitation, or beneficiary." } }, "description": "User that created the record when available to the current organization." }, "created_at": { "type": "string", "example": "2026-07-04T09:30:00+00:00", "format": "date-time", "description": "Timestamp for when created occurred, formatted as ISO 8601 when available." }, "updated_at": { "type": "string", "example": "2026-07-04T10:15:00+00:00", "format": "date-time", "description": "Timestamp for when updated occurred, formatted as ISO 8601 when available." } }, "description": "Primary response payload for this request." } }, "required": [ "success", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **404**: Resource not found. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### POST /api/v1/releases/{release_id} Operation: `updateRelease` Update Release Update Release. Use it to draft releases, update metadata, attach artwork and tracks, define rights, choose territories, and prepare releases for review and delivery. It applies the requested change and returns the updated resource, validation result, or action status needed for the next API step. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `release_id` in path (string, required): Public release reference returned by the API. - `X-User-Id` in header (string, required): Required user_id for catalog ownership and quota context. The client must also have users:act-as. #### Request body Multipart request payload. Required. **multipart/form-data** ```json { "type": "object", "additionalProperties": true, "properties": { "title": { "type": "string", "example": "Midnight Atlas", "description": "Catalog or content title shown in the dashboard and API responses." }, "cover_art": { "description": "Binary cover-art image file. Use JPG or PNG artwork that meets store artwork requirements.", "type": [ "string", "null" ], "format": "binary" }, "label": { "type": "string", "example": "Night Shift Records", "description": "Label name attached to the release metadata." }, "copyright_material": { "type": "boolean", "example": false, "description": "Whether the submitter has indicated that copyright-sensitive material is present." }, "copyright_links": { "type": "array", "items": { "type": "string", "format": "uri", "example": "https://rights.northstar-distribution.co.uk/midnight-atlas-license.pdf", "description": "URL to a license, permission document, or rights note for declared copyrighted material." }, "description": "Supporting URLs for rights review when copyright material is declared." }, "upc": { "type": "string", "example": "5054429191012", "description": "UPC supplied for the release, or omitted when one should be assigned later." }, "reference": { "type": "string", "example": "NSD-2026-041", "description": "Human-readable catalog or billing reference shown in the dashboard." }, "remix_version": { "type": "string", "example": "", "description": "Version label such as Original Mix, Radio Edit, or Remix." }, "genre": { "type": "string", "example": "Electronic", "description": "Primary release or track genre selected from supported values." }, "secondary_genre": { "type": "string", "example": "Ambient", "description": "Optional secondary genre used for more precise metadata." }, "language": { "type": "string", "example": "English", "description": "Primary language value used for profile, release, or track metadata." }, "explicit_content": { "type": "boolean", "example": false, "description": "Whether the release or track is marked as explicit." }, "format": { "type": "string", "example": "single", "description": "Release format, such as single, EP, or album." }, "description": { "type": "string", "example": "Updated delivery-ready metadata for Midnight Atlas.", "description": "Human-readable description for this record or workflow." }, "artists": { "type": "array", "items": { "type": "object", "additionalProperties": false, "properties": { "artist_id": { "type": "string", "example": "6f209ac7-d82c-4c8f-9d3e-bfe39c0df802", "format": "uuid", "description": "Public artist reference returned by the artists API." }, "type": { "type": "string", "example": "Primary Artist", "description": "Artist credit role for this release or track, such as Primary Artist or Featured Artist." } }, "required": [ "artist_id", "type" ] }, "description": "Artists credited or attached to this catalog record." } }, "required": [ "title" ] } ``` #### Responses - **200**: Update Release succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "Release updated.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." }, "data": { "type": "object", "additionalProperties": true, "properties": { "release_id": { "type": "string", "example": "b7a15d95-58f6-4f67-b5d1-89f4f5bfb4d8", "format": "uuid", "description": "Stable public release reference. Use this value in related endpoint paths and request bodies." }, "title": { "type": "string", "example": "Midnight Atlas", "description": "Catalog or content title shown in the dashboard and API responses." }, "status": { "type": "string", "example": "draft", "description": "Current lifecycle status for this record." }, "format": { "type": "string", "example": "single", "description": "Release format, such as single, EP, or album." }, "label": { "type": "string", "example": "Night Shift Records", "description": "Label name attached to the release metadata." }, "genre": { "type": "string", "example": "Electronic", "description": "Primary release or track genre selected from supported values." }, "secondary_genre": { "type": "string", "example": "Ambient", "description": "Optional secondary genre used for more precise metadata." }, "language": { "type": "string", "example": "English", "description": "Primary language value used for profile, release, or track metadata." }, "explicit_content": { "type": "boolean", "example": false, "description": "Whether the release or track is marked as explicit." }, "upc_code": { "type": "string", "example": "5054429191012", "description": "UPC assigned to the release, or null when it has not been assigned yet." }, "reference_number": { "type": "string", "example": "NSD-2026-041", "description": "Human-readable catalog or billing reference shown in the dashboard." }, "scheduled_date": { "type": "string", "example": "2026-08-21", "format": "date", "description": "Scheduled release date used for delivery planning and catalog display." }, "original_release_date": { "type": "string", "example": "2026-08-21", "format": "date", "description": "Calendar date for original release." }, "copyright_detection_enabled": { "type": "boolean", "example": true, "description": "Whether copyright checking is enabled for the organization or release workflow." }, "price_category": { "type": "string", "example": "mid", "description": "Release price tier or commercial category used for store delivery and billing decisions." }, "territories": { "type": "array", "items": { "type": "string", "example": "GB" }, "description": "Territory codes where the release or rights metadata should apply." }, "distribution": { "type": "array", "items": { "type": "object", "additionalProperties": true, "properties": { "channel": { "type": "string", "example": "spotify", "description": "Delivery channel or store identifier using public snake_case values." }, "status": { "type": "string", "example": "selected", "description": "Current lifecycle status for this record." } } }, "description": "Delivery destinations and their organization-visible status values." }, "cover_art": { "type": "string", "example": "https://assets.spacemedia-docs.invalid/releases/midnight-atlas/cover.jpg", "format": "uri", "description": "Public media URL or asset reference for the uploaded image." }, "track_count": { "type": "integer", "example": 1, "description": "Number of track records visible in this context." }, "artists": { "type": "array", "items": { "type": "object", "additionalProperties": false, "properties": { "artist_id": { "type": "string", "example": "6f209ac7-d82c-4c8f-9d3e-bfe39c0df802", "format": "uuid", "description": "Public artist reference returned by the artists API." }, "name": { "type": "string", "example": "Nova Vale", "description": "Display name for this artists." }, "type": { "type": "string", "example": "Primary Artist", "description": "Artist credit role for this release or track, such as Primary Artist or Featured Artist." } }, "required": [ "artist_id", "type" ] }, "description": "Artists credited or attached to this catalog record." }, "created_by": { "type": "object", "additionalProperties": true, "properties": { "user_id": { "type": "string", "example": "7d2d9f72-c0a2-4d4b-9b6d-7caa942b8a71", "format": "uuid", "description": "Stable public user reference. Use this value in related endpoint paths and request bodies." }, "name": { "type": "string", "example": "Maya Chen", "description": "Display name for this created_by." }, "email": { "type": "string", "example": "maya.chen@northstar-distribution.co.uk", "description": "Email address associated with the account, member, invitation, or beneficiary." } }, "description": "User that created the record when available to the current organization." }, "created_at": { "type": "string", "example": "2026-07-04T09:30:00+00:00", "format": "date-time", "description": "Timestamp for when created occurred, formatted as ISO 8601 when available." }, "updated_at": { "type": "string", "example": "2026-07-04T10:15:00+00:00", "format": "date-time", "description": "Timestamp for when updated occurred, formatted as ISO 8601 when available." }, "description": { "type": "string", "example": "Updated delivery-ready metadata for Midnight Atlas.", "description": "Human-readable description for this record or workflow." } }, "description": "Primary response payload for this request." } }, "required": [ "success", "message", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **404**: Resource not found. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **422**: Validation failed for genre. The request was not applied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### DELETE /api/v1/releases/{release_id} Operation: `deleteRelease` Delete Release Delete Release. Use it to draft releases, update metadata, attach artwork and tracks, define rights, choose territories, and prepare releases for review and delivery. It removes, revokes, or cancels the target when permissions and resource state allow it, then returns a confirmation or policy error. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `release_id` in path (string, required): Public release reference returned by the API. #### Responses - **200**: Delete Release succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "Release deleted successfully.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." } }, "required": [ "success", "message" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **404**: Resource not found. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### POST /api/v1/releases/{release_id}/cover-art Operation: `updateReleaseCoverArt` Update Release Cover Art Upload replacement cover art for a release by release_id. The image must satisfy release artwork requirements before the release can pass readiness checks. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `release_id` in path (string, required): Public release reference returned by the API. #### Request body Multipart request payload. Required. **multipart/form-data** ```json { "type": "object", "additionalProperties": true, "properties": { "cover_art": { "type": "string", "description": "Binary cover-art image file. Use JPG or PNG artwork that meets store artwork requirements.", "format": "binary" } }, "required": [ "cover_art" ] } ``` #### Responses - **200**: Update Release Cover Art succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "Cover art updated.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." }, "data": { "type": "object", "additionalProperties": true, "properties": { "release_id": { "type": "string", "example": "b7a15d95-58f6-4f67-b5d1-89f4f5bfb4d8", "format": "uuid", "description": "Stable public release reference. Use this value in related endpoint paths and request bodies." }, "cover_art": { "type": "string", "example": "https://assets.spacemedia-docs.invalid/releases/midnight-atlas/cover.jpg", "format": "uri", "description": "Public media URL or asset reference for the uploaded image." } }, "description": "Primary response payload for this request." } }, "required": [ "success", "message", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **404**: Resource not found. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **422**: Validation failed for cover_art. The request was not applied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### POST /api/v1/releases/{release_id}/distribution Operation: `updateReleaseDistribution` Update Release Distribution Update delivery channel and territory selections for a release. Use public channel codes and territory codes that match the organization catalog configuration. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `release_id` in path (string, required): Public release reference returned by the API. #### Request body Request payload. Required. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "channels": { "type": "array", "items": { "type": "string", "example": "spotify" }, "description": "Delivery channel codes selected for the release, such as spotify, apple_music, or youtube_music." }, "territories": { "type": "array", "items": { "type": "string", "example": "GB" }, "description": "Territory codes where the release or rights metadata should apply." } }, "required": [ "channels" ] } ``` #### Responses - **200**: Update Release Distribution succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "Distribution settings updated.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." }, "data": { "type": "object", "additionalProperties": true, "properties": { "release_id": { "type": "string", "example": "b7a15d95-58f6-4f67-b5d1-89f4f5bfb4d8", "format": "uuid", "description": "Stable public release reference. Use this value in related endpoint paths and request bodies." }, "distribution": { "type": "array", "items": { "type": "object", "additionalProperties": true, "properties": { "channel": { "type": "string", "example": "spotify", "description": "Delivery channel or store identifier using public snake_case values." }, "status": { "type": "string", "example": "selected", "description": "Current lifecycle status for this record." } } }, "description": "Delivery destinations and their organization-visible status values." }, "territories": { "type": "array", "items": { "type": "string", "example": "GB" }, "description": "Territory codes where the release or rights metadata should apply." } }, "description": "Primary response payload for this request." } }, "required": [ "success", "message", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **404**: Resource not found. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **422**: Validation failed for channels. The request was not applied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### GET /api/v1/releases/{release_id}/edit-options Operation: `getReleaseEditOptions` Get Release Edit Options Return the labels, genres, languages, and artist credit types available when editing a release. The options are scoped to the release owner and authenticated organization. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `release_id` in path (string, required): Public release reference returned by the API. #### Responses - **200**: Release edit options were loaded for the release owner and authenticated organization. **application/json** ```json { "type": "object", "additionalProperties": false, "properties": { "labels": { "type": "array", "items": { "type": "string", "example": "Night Shift Records" }, "description": "Sorted label names available to the release owner, including the organization default label." }, "can_use_custom_labels": { "type": "boolean", "example": true, "description": "Whether the release editor can select a custom label name from the returned options." }, "default_label_name": { "type": "string", "example": "Northstar Distribution", "description": "Default label name configured for the organization that owns the release." }, "genres": { "type": "array", "items": { "type": "string", "example": "Electronic" }, "description": "Supported music genres available for release and track metadata." }, "languages": { "type": "array", "items": { "type": "string", "example": "English" }, "description": "Supported language names available for release and track metadata." }, "artist_types": { "type": "array", "items": { "type": "string", "example": "Primary Artist" }, "description": "Supported artist credit roles available for release and track contributors." } }, "required": [ "labels", "can_use_custom_labels", "default_label_name", "genres", "languages", "artist_types" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **404**: Resource not found. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### POST /api/v1/releases/{release_id}/license Operation: `updateReleaseLicense` Update Release License Update release rights and licensing metadata, including dates, rights holder names, price category, license type, and territory availability. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `release_id` in path (string, required): Public release reference returned by the API. #### Request body Request payload. Required. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "price_category": { "type": "string", "example": "mid", "description": "Release price tier or commercial category used for store delivery and billing decisions." }, "digital_release_date": { "type": "string", "example": "2026-08-21", "format": "date", "description": "Calendar date for digital release." }, "original_release_date": { "type": "string", "example": "2026-08-21", "format": "date", "description": "Calendar date for original release." }, "license_type": { "type": "string", "example": "copyright", "description": "Rights model for the release, such as original, licensed, remix, cover, or another supported catalog type." }, "license_holder_year": { "type": "integer", "example": 2026, "description": "Year associated with the rights holder for the release or track metadata." }, "license_holder_name": { "type": "string", "example": "Night Shift Records Ltd", "description": "Legal name of the person or company that holds the relevant rights for the release or track." }, "sound_recordings_copyright_year": { "type": "integer", "example": 2026, "description": "Year associated with the sound recording copyright line for the release." }, "sound_recordings_copyright_name": { "type": "string", "example": "Night Shift Records Ltd", "description": "Legal name shown on the sound recording copyright line for the release." }, "territories": { "type": "array", "items": { "type": "string", "example": "GB" }, "description": "Territory codes where the release or rights metadata should apply." } }, "required": [ "price_category", "digital_release_date", "license_type", "license_holder_year", "license_holder_name" ] } ``` #### Responses - **200**: Update Release License succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "Release license updated.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." }, "data": { "type": "object", "additionalProperties": true, "properties": { "release_id": { "type": "string", "example": "b7a15d95-58f6-4f67-b5d1-89f4f5bfb4d8", "format": "uuid", "description": "Stable public release reference. Use this value in related endpoint paths and request bodies." }, "title": { "type": "string", "example": "Midnight Atlas", "description": "Catalog or content title shown in the dashboard and API responses." }, "status": { "type": "string", "example": "draft", "description": "Current lifecycle status for this record." }, "format": { "type": "string", "example": "single", "description": "Release format, such as single, EP, or album." }, "label": { "type": "string", "example": "Night Shift Records", "description": "Label name attached to the release metadata." }, "genre": { "type": "string", "example": "Electronic", "description": "Primary release or track genre selected from supported values." }, "secondary_genre": { "type": "string", "example": "Ambient", "description": "Optional secondary genre used for more precise metadata." }, "language": { "type": "string", "example": "English", "description": "Primary language value used for profile, release, or track metadata." }, "explicit_content": { "type": "boolean", "example": false, "description": "Whether the release or track is marked as explicit." }, "upc_code": { "type": "string", "example": "5054429191012", "description": "UPC assigned to the release, or null when it has not been assigned yet." }, "reference_number": { "type": "string", "example": "NSD-2026-041", "description": "Human-readable catalog or billing reference shown in the dashboard." }, "scheduled_date": { "type": "string", "example": "2026-08-21", "format": "date", "description": "Scheduled release date used for delivery planning and catalog display." }, "original_release_date": { "type": "string", "example": "2026-08-21", "format": "date", "description": "Calendar date for original release." }, "copyright_detection_enabled": { "type": "boolean", "example": true, "description": "Whether copyright checking is enabled for the organization or release workflow." }, "price_category": { "type": "string", "example": "mid", "description": "Release price tier or commercial category used for store delivery and billing decisions." }, "territories": { "type": "array", "items": { "type": "string", "example": "GB" }, "description": "Territory codes where the release or rights metadata should apply." }, "distribution": { "type": "array", "items": { "type": "object", "additionalProperties": true, "properties": { "channel": { "type": "string", "example": "spotify", "description": "Delivery channel or store identifier using public snake_case values." }, "status": { "type": "string", "example": "selected", "description": "Current lifecycle status for this record." } } }, "description": "Delivery destinations and their organization-visible status values." }, "cover_art": { "type": "string", "example": "https://assets.spacemedia-docs.invalid/releases/midnight-atlas/cover.jpg", "format": "uri", "description": "Public media URL or asset reference for the uploaded image." }, "track_count": { "type": "integer", "example": 1, "description": "Number of track records visible in this context." }, "artists": { "type": "array", "items": { "type": "object", "additionalProperties": false, "properties": { "artist_id": { "type": "string", "example": "6f209ac7-d82c-4c8f-9d3e-bfe39c0df802", "format": "uuid", "description": "Public artist reference returned by the artists API." }, "name": { "type": "string", "example": "Nova Vale", "description": "Display name for this artists." }, "type": { "type": "string", "example": "Primary Artist", "description": "Artist credit role for this release or track, such as Primary Artist or Featured Artist." } }, "required": [ "artist_id", "type" ] }, "description": "Artists credited or attached to this catalog record." }, "created_by": { "type": "object", "additionalProperties": true, "properties": { "user_id": { "type": "string", "example": "7d2d9f72-c0a2-4d4b-9b6d-7caa942b8a71", "format": "uuid", "description": "Stable public user reference. Use this value in related endpoint paths and request bodies." }, "name": { "type": "string", "example": "Maya Chen", "description": "Display name for this created_by." }, "email": { "type": "string", "example": "maya.chen@northstar-distribution.co.uk", "description": "Email address associated with the account, member, invitation, or beneficiary." } }, "description": "User that created the record when available to the current organization." }, "created_at": { "type": "string", "example": "2026-07-04T09:30:00+00:00", "format": "date-time", "description": "Timestamp for when created occurred, formatted as ISO 8601 when available." }, "updated_at": { "type": "string", "example": "2026-07-04T10:15:00+00:00", "format": "date-time", "description": "Timestamp for when updated occurred, formatted as ISO 8601 when available." } }, "description": "Primary response payload for this request." } }, "required": [ "success", "message", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **404**: Resource not found. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **422**: Validation failed for price_category. The request was not applied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### GET /api/v1/releases/{release_id}/pre-qc Operation: `getReleaseReadinessChecks` View Release Readiness Checks Run release readiness checks before submission. The response highlights metadata, rights, artwork, audio, and delivery issues that should be fixed before sending the release to review. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `release_id` in path (string, required): Public release reference returned by the API. #### Responses - **200**: View Release Readiness Checks succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "data": { "type": "object", "additionalProperties": true, "properties": { "release": { "type": "object", "additionalProperties": true, "properties": { "release_id": { "type": "string", "example": "b7a15d95-58f6-4f67-b5d1-89f4f5bfb4d8", "format": "uuid", "description": "Stable public release reference. Use this value in related endpoint paths and request bodies." }, "title": { "type": "string", "example": "Midnight Atlas", "description": "Catalog or content title shown in the dashboard and API responses." }, "status": { "type": "string", "example": "draft", "description": "Current lifecycle status for this record." } }, "description": "Release summary or nested release object connected to this workflow." }, "passed": { "type": "boolean", "example": false, "description": "Whether the readiness or validation check passed." }, "checks": { "type": "array", "items": { "type": "object", "additionalProperties": true, "properties": { "code": { "type": "string", "example": "missing_license_date", "description": "code for checks." }, "severity": { "type": "string", "example": "warning", "description": "severity for checks." }, "message": { "type": "string", "example": "Add original release date before submission.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." } } }, "description": "Readiness, copyright, or validation checks returned for the release or workflow." } }, "description": "Primary response payload for this request." } }, "required": [ "success", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **404**: Resource not found. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### POST /api/v1/releases/{release_id}/submit Operation: `submitRelease` Submit Release Submit an organization-owned draft release for review after metadata, cover art, tracks, rights, territories, and destinations are complete. The response confirms the next review state or explains blocking readiness issues. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `release_id` in path (string, required): Public release reference returned by the API. #### Responses - **200**: Submit Release succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "Release submitted.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." } }, "required": [ "success", "message" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **404**: Resource not found. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### GET /api/v1/releases/{release_id}/tracks Operation: `listReleaseTracks` List Release Tracks List Release Tracks. Use it to draft releases, update metadata, attach artwork and tracks, define rights, choose territories, and prepare releases for review and delivery. It returns public references and organization-visible fields only, so clients can safely use returned values in follow-up API calls. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `release_id` in path (string, required): Public release reference returned by the API. #### Responses - **200**: List Release Tracks succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "data": { "type": "array", "items": { "type": "object", "additionalProperties": true, "properties": { "track_id": { "type": "string", "example": "e454b6f8-df5b-49db-9b9f-916f74ec1f21", "format": "uuid", "description": "Stable public track reference. Use this value in related endpoint paths and request bodies." }, "release": { "type": "object", "additionalProperties": true, "properties": { "release_id": { "type": "string", "example": "b7a15d95-58f6-4f67-b5d1-89f4f5bfb4d8", "format": "uuid", "description": "Stable public release reference. Use this value in related endpoint paths and request bodies." }, "title": { "type": "string", "example": "Midnight Atlas", "description": "Catalog or content title shown in the dashboard and API responses." }, "status": { "type": "string", "example": "draft", "description": "Current lifecycle status for this record." } }, "description": "Release summary or nested release object connected to this workflow." }, "title": { "type": "string", "example": "Midnight Atlas", "description": "Catalog or content title shown in the dashboard and API responses." }, "artists": { "type": "array", "items": { "type": "object", "additionalProperties": false, "properties": { "artist_id": { "type": "string", "example": "6f209ac7-d82c-4c8f-9d3e-bfe39c0df802", "format": "uuid", "description": "Public artist reference returned by the artists API." }, "name": { "type": "string", "example": "Nova Vale", "description": "Display name for this artists." }, "type": { "type": "string", "example": "Primary Artist", "description": "Artist credit role for this release or track, such as Primary Artist or Featured Artist." } }, "required": [ "artist_id", "type" ] }, "description": "Artists credited or attached to this catalog record." }, "duration": { "type": "integer", "example": 196, "description": "Track duration in seconds or a display-ready duration value." }, "language": { "type": "string", "example": "English", "description": "Primary language value used for profile, release, or track metadata." }, "primary_genre": { "type": "string", "example": "Electronic", "description": "Primary track genre selected from supported values." }, "secondary_genre": { "type": "string", "example": "Ambient", "description": "Optional secondary genre used for more precise metadata." }, "track_version": { "type": "string", "example": "Original Mix", "description": "Version label for the track, such as remix, radio edit, instrumental, or acoustic version." }, "isrc_code": { "type": "string", "example": "GBSMU2600001", "description": "ISRC assigned to the track, or blank when one should be assigned later." }, "iswc_code": { "type": "string", "example": "T0345246801", "description": "ISWC for the composition when available." }, "is_available_separately": { "type": "boolean", "example": true, "description": "Whether the track can be distributed or sold separately from the release when supported by selected stores." }, "is_parental_advisory": { "type": "boolean", "example": false, "description": "Whether the track should be marked with an explicit or parental advisory flag." }, "license_holder_year": { "type": "integer", "example": 2026, "description": "Year associated with the rights holder for the release or track metadata." }, "license_holder_name": { "type": "string", "example": "Night Shift Records Ltd", "description": "Legal name of the person or company that holds the relevant rights for the release or track." }, "playback_url": { "type": "string", "example": "https://media.spacemedia-docs.invalid/audio/midnight-atlas/master.wav", "format": "uri", "description": "Public URL returned for this resource or action." }, "preview_url": { "type": "string", "example": "https://media.spacemedia-docs.invalid/audio/midnight-atlas/preview.mp3", "format": "uri", "description": "Public URL returned for this resource or action." }, "documents_requested": { "type": "boolean", "example": false, "description": "Whether the track currently requires supporting rights or copyright documentation before review can continue." }, "created_at": { "type": "string", "example": "2026-07-04T09:30:00+00:00", "format": "date-time", "description": "Timestamp for when created occurred, formatted as ISO 8601 when available." }, "updated_at": { "type": "string", "example": "2026-07-04T10:15:00+00:00", "format": "date-time", "description": "Timestamp for when updated occurred, formatted as ISO 8601 when available." } } }, "description": "Primary response payload for this request." }, "meta": { "type": "object", "additionalProperties": true, "properties": { "current_page": { "type": "integer", "example": 1, "description": "current page for meta." }, "last_page": { "type": "integer", "example": 1, "description": "last page for meta." }, "per_page": { "type": "integer", "example": 20, "description": "per page for meta." }, "total": { "type": "integer", "example": 1, "description": "Total number of records matching the current filters." }, "from": { "type": "integer", "example": 1, "description": "from for meta." }, "to": { "type": "integer", "example": 1, "description": "to for meta." } }, "description": "Pagination, filter, or response metadata for this request." } }, "required": [ "success", "data", "meta" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **404**: Resource not found. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### POST /api/v1/releases/{release_id}/tracks/reorder Operation: `reorderReleaseTracks` Reorder Release Tracks Set the final track order for a release by submitting track_ids in sequence. Use this before release submission so DSP metadata reflects the intended running order. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `release_id` in path (string, required): Public release reference returned by the API. #### Request body Request payload. Required. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "track_ids": { "type": "array", "items": { "type": "string", "example": "e454b6f8-df5b-49db-9b9f-916f74ec1f21", "format": "uuid" }, "description": "Ordered public track references used to assign, reorder, or split revenue for tracks visible to the organization." } }, "required": [ "track_ids" ] } ``` #### Responses - **200**: Reorder Release Tracks succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "Track order updated.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." }, "data": { "type": "object", "additionalProperties": true, "properties": { "release_id": { "type": "string", "example": "b7a15d95-58f6-4f67-b5d1-89f4f5bfb4d8", "format": "uuid", "description": "Stable public release reference. Use this value in related endpoint paths and request bodies." }, "track_ids": { "type": "array", "items": { "type": "string", "example": "e454b6f8-df5b-49db-9b9f-916f74ec1f21", "format": "uuid" }, "description": "Ordered public track references used to assign, reorder, or split revenue for tracks visible to the organization." } }, "description": "Primary response payload for this request." } }, "required": [ "success", "message", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **404**: Resource not found. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **422**: Validation failed for track_ids. The request was not applied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### POST /api/v1/releases/migrate Operation: `importReleasesFromMusicUrls` Import Releases From Music URLs Import one or more visible Spotify album or track URLs into draft release records for the authenticated organization. The endpoint applies the same release creation limits and permissions as the dashboard import workflow, returns the imported releases, and never accepts organization selectors. Security: ```json [ { "BearerAuth": [] } ] ``` #### Request body Request payload. Required. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "urls": { "type": "array", "items": { "type": "string", "example": "https://open.spotify.com/album/4Gj9kL2mN8rT6bY1xQvP3z", "format": "uri" }, "description": "External catalog, DSP, or distributor URLs that identify the release being migrated into SpaceMedia." }, "distributor": { "type": "string", "example": "distrokid", "description": "Name of the current or previous distributor for the release migration request." } }, "required": [ "urls" ] } ``` #### Responses - **200**: Import Releases From Music URLs succeeded and returns the documented response body. **application/json** ```json { "type": "object", "required": [ "success", "message", "data" ], "properties": { "success": { "type": "boolean", "example": true }, "message": { "type": "string", "example": "Release imported successfully." }, "data": { "type": "object", "required": [ "releases" ], "properties": { "releases": { "type": "array", "items": { "$ref": "#/components/schemas/Release" } } } } } } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **422**: Validation failed for urls. The request was not applied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ## Tracks Upload audio, create and update track metadata, attach tracks to releases, inspect upload progress, and manage supporting documents. ### GET /api/v1/tracks Operation: `listTracks` List Tracks List Tracks. Use it to upload audio, maintain track metadata, manage contributor and rights information, attach documents, and assign tracks to visible releases. It returns public references and organization-visible fields only, so clients can safely use returned values in follow-up API calls. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `search` in query (string): Search term for matching visible records. - `page` in query (integer): Page number to return. - `size` in query (integer): Number of records per page. - `sort` in query (string): Sort direction for creation date. - `X-User-Id` in header (string): Optional user_id to perform an allowed action for a user in the same organization. #### Responses - **200**: List Tracks succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "data": { "type": "array", "items": { "type": "object", "additionalProperties": true, "properties": { "track_id": { "type": "string", "example": "e454b6f8-df5b-49db-9b9f-916f74ec1f21", "format": "uuid", "description": "Stable public track reference. Use this value in related endpoint paths and request bodies." }, "release": { "type": "object", "additionalProperties": true, "properties": { "release_id": { "type": "string", "example": "b7a15d95-58f6-4f67-b5d1-89f4f5bfb4d8", "format": "uuid", "description": "Stable public release reference. Use this value in related endpoint paths and request bodies." }, "title": { "type": "string", "example": "Midnight Atlas", "description": "Catalog or content title shown in the dashboard and API responses." }, "status": { "type": "string", "example": "draft", "description": "Current lifecycle status for this record." } }, "description": "Release summary or nested release object connected to this workflow." }, "title": { "type": "string", "example": "Midnight Atlas", "description": "Catalog or content title shown in the dashboard and API responses." }, "artists": { "type": "array", "items": { "type": "object", "additionalProperties": false, "properties": { "artist_id": { "type": "string", "example": "6f209ac7-d82c-4c8f-9d3e-bfe39c0df802", "format": "uuid", "description": "Public artist reference returned by the artists API." }, "name": { "type": "string", "example": "Nova Vale", "description": "Display name for this artists." }, "type": { "type": "string", "example": "Primary Artist", "description": "Artist credit role for this release or track, such as Primary Artist or Featured Artist." } }, "required": [ "artist_id", "type" ] }, "description": "Artists credited or attached to this catalog record." }, "duration": { "type": "integer", "example": 196, "description": "Track duration in seconds or a display-ready duration value." }, "language": { "type": "string", "example": "English", "description": "Primary language value used for profile, release, or track metadata." }, "primary_genre": { "type": "string", "example": "Electronic", "description": "Primary track genre selected from supported values." }, "secondary_genre": { "type": "string", "example": "Ambient", "description": "Optional secondary genre used for more precise metadata." }, "track_version": { "type": "string", "example": "Original Mix", "description": "Version label for the track, such as remix, radio edit, instrumental, or acoustic version." }, "isrc_code": { "type": "string", "example": "GBSMU2600001", "description": "ISRC assigned to the track, or blank when one should be assigned later." }, "iswc_code": { "type": "string", "example": "T0345246801", "description": "ISWC for the composition when available." }, "is_available_separately": { "type": "boolean", "example": true, "description": "Whether the track can be distributed or sold separately from the release when supported by selected stores." }, "is_parental_advisory": { "type": "boolean", "example": false, "description": "Whether the track should be marked with an explicit or parental advisory flag." }, "license_holder_year": { "type": "integer", "example": 2026, "description": "Year associated with the rights holder for the release or track metadata." }, "license_holder_name": { "type": "string", "example": "Night Shift Records Ltd", "description": "Legal name of the person or company that holds the relevant rights for the release or track." }, "playback_url": { "type": "string", "example": "https://media.spacemedia-docs.invalid/audio/midnight-atlas/master.wav", "format": "uri", "description": "Public URL returned for this resource or action." }, "preview_url": { "type": "string", "example": "https://media.spacemedia-docs.invalid/audio/midnight-atlas/preview.mp3", "format": "uri", "description": "Public URL returned for this resource or action." }, "documents_requested": { "type": "boolean", "example": false, "description": "Whether the track currently requires supporting rights or copyright documentation before review can continue." }, "created_at": { "type": "string", "example": "2026-07-04T09:30:00+00:00", "format": "date-time", "description": "Timestamp for when created occurred, formatted as ISO 8601 when available." }, "updated_at": { "type": "string", "example": "2026-07-04T10:15:00+00:00", "format": "date-time", "description": "Timestamp for when updated occurred, formatted as ISO 8601 when available." } } }, "description": "Primary response payload for this request." }, "meta": { "type": "object", "additionalProperties": true, "properties": { "current_page": { "type": "integer", "example": 1, "description": "current page for meta." }, "last_page": { "type": "integer", "example": 1, "description": "last page for meta." }, "per_page": { "type": "integer", "example": 20, "description": "per page for meta." }, "total": { "type": "integer", "example": 1, "description": "Total number of records matching the current filters." }, "from": { "type": "integer", "example": 1, "description": "from for meta." }, "to": { "type": "integer", "example": 1, "description": "to for meta." } }, "description": "Pagination, filter, or response metadata for this request." } }, "required": [ "success", "data", "meta" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **422**: Validation failed for search. The request was not applied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### POST /api/v1/tracks Operation: `createTrack` Create Track Create a track from audio_file_id plus title, artists, language, genre, rights, identifiers, lyrics, and availability metadata. The response returns the stable track_id for release assignment. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `X-User-Id` in header (string, required): Required user_id for catalog ownership and quota context. The client must also have users:act-as. #### Request body Request payload. Required. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "title": { "type": "string", "example": "Midnight Atlas", "description": "Catalog or content title shown in the dashboard and API responses." }, "release_id": { "type": "string", "format": "uuid", "example": "b7a15d95-58f6-4f67-b5d1-89f4f5bfb4d8", "description": "Public release reference returned by the releases API. Include it when the new track belongs to a release." }, "audio_file_id": { "type": "string", "example": "audio_1783157400_6f9c2b8e4d1a", "description": "Temporary audio upload reference returned by the upload endpoint." }, "artists": { "type": "array", "items": { "type": "object", "additionalProperties": false, "properties": { "artist_id": { "type": "string", "example": "6f209ac7-d82c-4c8f-9d3e-bfe39c0df802", "format": "uuid", "description": "Public artist reference returned by the artists API." }, "type": { "type": "string", "example": "Primary Artist", "description": "Artist credit role for this release or track, such as Primary Artist or Featured Artist." } }, "required": [ "artist_id", "type" ] }, "description": "Artists credited or attached to this catalog record." }, "language": { "type": "string", "example": "English", "description": "Primary language value used for profile, release, or track metadata." }, "primary_genre": { "type": "string", "example": "Electronic", "description": "Primary track genre selected from supported values." }, "iswc_code": { "type": "string", "example": "T-034.524.680-1", "description": "ISWC for the composition when available." }, "isrc_code": { "type": "string", "example": "GB-SMU-26-00001", "description": "ISRC assigned to the track, or blank when one should be assigned later." }, "lyrics": { "description": "Lyrics text when supplied for the track.", "type": [ "string", "null" ] }, "is_available_separately": { "type": "boolean", "example": true, "description": "Whether the track can be distributed or sold separately from the release when supported by selected stores." }, "is_parental_advisory": { "type": "boolean", "example": false, "description": "Whether the track should be marked with an explicit or parental advisory flag." }, "license_holder_year": { "type": "integer", "example": 2026, "description": "Year associated with the rights holder for the release or track metadata." }, "license_holder_name": { "type": "string", "example": "Night Shift Records Ltd", "description": "Legal name of the person or company that holds the relevant rights for the release or track." }, "notes": { "type": "string", "example": "Original mix for DSP delivery.", "description": "Operational notes visible to permitted organization users during review." }, "metadata": { "type": "object", "additionalProperties": true, "properties": { "version": { "type": "string", "example": "Original Mix", "description": "version for metadata." }, "secondary_genre": { "type": "string", "example": "Ambient", "description": "Optional secondary genre used for more precise metadata." } }, "description": "Additional structured metadata for this resource." }, "duration": { "type": "integer", "example": 196, "description": "Track duration in seconds or a display-ready duration value." }, "links": { "type": "array", "items": { "type": "string", "example": "https://media.spacemedia-docs.invalid/audio/midnight-atlas/master.wav", "format": "uri" }, "description": "External reference links for the track, such as preview, lyric, rights, or platform URLs relevant to catalog review." } }, "required": [ "title", "audio_file_id", "artists", "language", "license_holder_year", "license_holder_name", "links" ] } ``` #### Responses - **200**: Create Track succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "Track created.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." }, "data": { "type": "object", "additionalProperties": true, "properties": { "track_id": { "type": "string", "example": "e454b6f8-df5b-49db-9b9f-916f74ec1f21", "format": "uuid", "description": "Stable public track reference. Use this value in related endpoint paths and request bodies." }, "release": { "type": "object", "additionalProperties": true, "properties": { "release_id": { "type": "string", "example": "b7a15d95-58f6-4f67-b5d1-89f4f5bfb4d8", "format": "uuid", "description": "Stable public release reference. Use this value in related endpoint paths and request bodies." }, "title": { "type": "string", "example": "Midnight Atlas", "description": "Catalog or content title shown in the dashboard and API responses." }, "status": { "type": "string", "example": "draft", "description": "Current lifecycle status for this record." } }, "description": "Release summary or nested release object connected to this workflow." }, "title": { "type": "string", "example": "Midnight Atlas", "description": "Catalog or content title shown in the dashboard and API responses." }, "artists": { "type": "array", "items": { "type": "object", "additionalProperties": false, "properties": { "artist_id": { "type": "string", "example": "6f209ac7-d82c-4c8f-9d3e-bfe39c0df802", "format": "uuid", "description": "Public artist reference returned by the artists API." }, "name": { "type": "string", "example": "Nova Vale", "description": "Display name for this artists." }, "type": { "type": "string", "example": "Primary Artist", "description": "Artist credit role for this release or track, such as Primary Artist or Featured Artist." } }, "required": [ "artist_id", "type" ] }, "description": "Artists credited or attached to this catalog record." }, "duration": { "type": "integer", "example": 196, "description": "Track duration in seconds or a display-ready duration value." }, "language": { "type": "string", "example": "English", "description": "Primary language value used for profile, release, or track metadata." }, "primary_genre": { "type": "string", "example": "Electronic", "description": "Primary track genre selected from supported values." }, "secondary_genre": { "type": "string", "example": "Ambient", "description": "Optional secondary genre used for more precise metadata." }, "track_version": { "type": "string", "example": "Original Mix", "description": "Version label for the track, such as remix, radio edit, instrumental, or acoustic version." }, "isrc_code": { "type": "string", "example": "GBSMU2600001", "description": "ISRC assigned to the track, or blank when one should be assigned later." }, "iswc_code": { "type": "string", "example": "T0345246801", "description": "ISWC for the composition when available." }, "is_available_separately": { "type": "boolean", "example": true, "description": "Whether the track can be distributed or sold separately from the release when supported by selected stores." }, "is_parental_advisory": { "type": "boolean", "example": false, "description": "Whether the track should be marked with an explicit or parental advisory flag." }, "license_holder_year": { "type": "integer", "example": 2026, "description": "Year associated with the rights holder for the release or track metadata." }, "license_holder_name": { "type": "string", "example": "Night Shift Records Ltd", "description": "Legal name of the person or company that holds the relevant rights for the release or track." }, "playback_url": { "type": "string", "example": "https://media.spacemedia-docs.invalid/audio/midnight-atlas/master.wav", "format": "uri", "description": "Public URL returned for this resource or action." }, "preview_url": { "type": "string", "example": "https://media.spacemedia-docs.invalid/audio/midnight-atlas/preview.mp3", "format": "uri", "description": "Public URL returned for this resource or action." }, "documents_requested": { "type": "boolean", "example": false, "description": "Whether the track currently requires supporting rights or copyright documentation before review can continue." }, "created_at": { "type": "string", "example": "2026-07-04T09:30:00+00:00", "format": "date-time", "description": "Timestamp for when created occurred, formatted as ISO 8601 when available." }, "updated_at": { "type": "string", "example": "2026-07-04T10:15:00+00:00", "format": "date-time", "description": "Timestamp for when updated occurred, formatted as ISO 8601 when available." } }, "description": "Primary response payload for this request." } }, "required": [ "success", "message", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **422**: Validation failed for audio_file_id. The request was not applied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### POST /api/v1/tracks/{track_id} Operation: `updateTrack` Update Track Update track metadata, audio reference, rights, identifiers, lyrics, and platform links by track_id. Only tracks visible to the organization can be changed. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `track_id` in path (string, required): Public track reference returned by the API. - `X-User-Id` in header (string, required): Required user_id for catalog ownership and quota context. The client must also have users:act-as. #### Request body Request payload. Required. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "title": { "type": "string", "example": "Midnight Atlas", "description": "Catalog or content title shown in the dashboard and API responses." }, "audio_file_id": { "type": "string", "example": "audio_1783157400_6f9c2b8e4d1a", "description": "Temporary audio upload reference returned by the upload endpoint." }, "artists": { "type": "array", "items": { "type": "object", "additionalProperties": false, "properties": { "artist_id": { "type": "string", "example": "6f209ac7-d82c-4c8f-9d3e-bfe39c0df802", "format": "uuid", "description": "Public artist reference returned by the artists API." }, "type": { "type": "string", "example": "Primary Artist", "description": "Artist credit role for this release or track, such as Primary Artist or Featured Artist." } }, "required": [ "artist_id", "type" ] }, "description": "Artists credited or attached to this catalog record." }, "language": { "type": "string", "example": "English", "description": "Primary language value used for profile, release, or track metadata." }, "primary_genre": { "type": "string", "example": "Electronic", "description": "Primary track genre selected from supported values." }, "iswc_code": { "type": "string", "example": "T-034.524.680-1", "description": "ISWC for the composition when available." }, "isrc_code": { "type": "string", "example": "GB-SMU-26-00001", "description": "ISRC assigned to the track, or blank when one should be assigned later." }, "lyrics": { "description": "Lyrics text when supplied for the track.", "type": [ "string", "null" ] }, "is_available_separately": { "type": "boolean", "example": true, "description": "Whether the track can be distributed or sold separately from the release when supported by selected stores." }, "is_parental_advisory": { "type": "boolean", "example": false, "description": "Whether the track should be marked with an explicit or parental advisory flag." }, "license_holder_year": { "type": "integer", "example": 2026, "description": "Year associated with the rights holder for the release or track metadata." }, "license_holder_name": { "type": "string", "example": "Night Shift Records Ltd", "description": "Legal name of the person or company that holds the relevant rights for the release or track." }, "notes": { "type": "string", "example": "Updated production notes for the delivery team.", "description": "Operational notes visible to permitted organization users during review." }, "metadata": { "type": "object", "additionalProperties": true, "properties": { "version": { "type": "string", "example": "Original Mix", "description": "version for metadata." }, "secondary_genre": { "type": "string", "example": "Ambient", "description": "Optional secondary genre used for more precise metadata." } }, "description": "Additional structured metadata for this resource." }, "duration": { "type": "integer", "example": 196, "description": "Track duration in seconds or a display-ready duration value." }, "links": { "type": "array", "items": { "type": "string", "example": "https://media.spacemedia-docs.invalid/audio/midnight-atlas/master.wav", "format": "uri" }, "description": "External reference links for the track, such as preview, lyric, rights, or platform URLs relevant to catalog review." } }, "required": [ "title" ] } ``` #### Responses - **200**: Update Track succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "Track updated.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." }, "data": { "type": "object", "additionalProperties": true, "properties": { "track_id": { "type": "string", "example": "e454b6f8-df5b-49db-9b9f-916f74ec1f21", "format": "uuid", "description": "Stable public track reference. Use this value in related endpoint paths and request bodies." }, "release": { "type": "object", "additionalProperties": true, "properties": { "release_id": { "type": "string", "example": "b7a15d95-58f6-4f67-b5d1-89f4f5bfb4d8", "format": "uuid", "description": "Stable public release reference. Use this value in related endpoint paths and request bodies." }, "title": { "type": "string", "example": "Midnight Atlas", "description": "Catalog or content title shown in the dashboard and API responses." }, "status": { "type": "string", "example": "draft", "description": "Current lifecycle status for this record." } }, "description": "Release summary or nested release object connected to this workflow." }, "title": { "type": "string", "example": "Midnight Atlas", "description": "Catalog or content title shown in the dashboard and API responses." }, "artists": { "type": "array", "items": { "type": "object", "additionalProperties": false, "properties": { "artist_id": { "type": "string", "example": "6f209ac7-d82c-4c8f-9d3e-bfe39c0df802", "format": "uuid", "description": "Public artist reference returned by the artists API." }, "name": { "type": "string", "example": "Nova Vale", "description": "Display name for this artists." }, "type": { "type": "string", "example": "Primary Artist", "description": "Artist credit role for this release or track, such as Primary Artist or Featured Artist." } }, "required": [ "artist_id", "type" ] }, "description": "Artists credited or attached to this catalog record." }, "duration": { "type": "integer", "example": 196, "description": "Track duration in seconds or a display-ready duration value." }, "language": { "type": "string", "example": "English", "description": "Primary language value used for profile, release, or track metadata." }, "primary_genre": { "type": "string", "example": "Electronic", "description": "Primary track genre selected from supported values." }, "secondary_genre": { "type": "string", "example": "Ambient", "description": "Optional secondary genre used for more precise metadata." }, "track_version": { "type": "string", "example": "Original Mix", "description": "Version label for the track, such as remix, radio edit, instrumental, or acoustic version." }, "isrc_code": { "type": "string", "example": "GBSMU2600001", "description": "ISRC assigned to the track, or blank when one should be assigned later." }, "iswc_code": { "type": "string", "example": "T0345246801", "description": "ISWC for the composition when available." }, "is_available_separately": { "type": "boolean", "example": true, "description": "Whether the track can be distributed or sold separately from the release when supported by selected stores." }, "is_parental_advisory": { "type": "boolean", "example": false, "description": "Whether the track should be marked with an explicit or parental advisory flag." }, "license_holder_year": { "type": "integer", "example": 2026, "description": "Year associated with the rights holder for the release or track metadata." }, "license_holder_name": { "type": "string", "example": "Night Shift Records Ltd", "description": "Legal name of the person or company that holds the relevant rights for the release or track." }, "playback_url": { "type": "string", "example": "https://media.spacemedia-docs.invalid/audio/midnight-atlas/master.wav", "format": "uri", "description": "Public URL returned for this resource or action." }, "preview_url": { "type": "string", "example": "https://media.spacemedia-docs.invalid/audio/midnight-atlas/preview.mp3", "format": "uri", "description": "Public URL returned for this resource or action." }, "documents_requested": { "type": "boolean", "example": false, "description": "Whether the track currently requires supporting rights or copyright documentation before review can continue." }, "created_at": { "type": "string", "example": "2026-07-04T09:30:00+00:00", "format": "date-time", "description": "Timestamp for when created occurred, formatted as ISO 8601 when available." }, "updated_at": { "type": "string", "example": "2026-07-04T10:15:00+00:00", "format": "date-time", "description": "Timestamp for when updated occurred, formatted as ISO 8601 when available." }, "notes": { "type": "string", "example": "Updated production notes for the delivery team.", "description": "Operational notes visible to permitted organization users during review." } }, "description": "Primary response payload for this request." } }, "required": [ "success", "message", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **404**: Resource not found. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **422**: Validation failed for isrc_code. The request was not applied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### DELETE /api/v1/tracks/{track_id} Operation: `deleteTrack` Delete Track Delete Track. Use it to upload audio, maintain track metadata, manage contributor and rights information, attach documents, and assign tracks to visible releases. It removes, revokes, or cancels the target when permissions and resource state allow it, then returns a confirmation or policy error. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `track_id` in path (string, required): Public track reference returned by the API. #### Responses - **200**: Delete Track succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "Track deleted successfully.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." } }, "required": [ "success", "message" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **404**: Resource not found. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### POST /api/v1/tracks/{track_id}/assign/{release_id} Operation: `assignTrackToRelease` Assign Track to Release Attach a visible track to a visible release by track_id and release_id. Use this after creating both resources and before ordering or submitting the release. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `track_id` in path (string, required): Public track reference returned by the API. - `release_id` in path (string, required): Public release reference returned by the API. #### Responses - **200**: Assign Track to Release succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "Track assigned to release.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." }, "data": { "type": "object", "additionalProperties": true, "properties": { "track_id": { "type": "string", "example": "e454b6f8-df5b-49db-9b9f-916f74ec1f21", "format": "uuid", "description": "Stable public track reference. Use this value in related endpoint paths and request bodies." }, "release": { "type": "object", "additionalProperties": true, "properties": { "release_id": { "type": "string", "example": "b7a15d95-58f6-4f67-b5d1-89f4f5bfb4d8", "format": "uuid", "description": "Stable public release reference. Use this value in related endpoint paths and request bodies." }, "title": { "type": "string", "example": "Midnight Atlas", "description": "Catalog or content title shown in the dashboard and API responses." }, "status": { "type": "string", "example": "draft", "description": "Current lifecycle status for this record." } }, "description": "Release summary or nested release object connected to this workflow." }, "title": { "type": "string", "example": "Midnight Atlas", "description": "Catalog or content title shown in the dashboard and API responses." }, "artists": { "type": "array", "items": { "type": "object", "additionalProperties": false, "properties": { "artist_id": { "type": "string", "example": "6f209ac7-d82c-4c8f-9d3e-bfe39c0df802", "format": "uuid", "description": "Public artist reference returned by the artists API." }, "name": { "type": "string", "example": "Nova Vale", "description": "Display name for this artists." }, "type": { "type": "string", "example": "Primary Artist", "description": "Artist credit role for this release or track, such as Primary Artist or Featured Artist." } }, "required": [ "artist_id", "type" ] }, "description": "Artists credited or attached to this catalog record." }, "duration": { "type": "integer", "example": 196, "description": "Track duration in seconds or a display-ready duration value." }, "language": { "type": "string", "example": "English", "description": "Primary language value used for profile, release, or track metadata." }, "primary_genre": { "type": "string", "example": "Electronic", "description": "Primary track genre selected from supported values." }, "secondary_genre": { "type": "string", "example": "Ambient", "description": "Optional secondary genre used for more precise metadata." }, "track_version": { "type": "string", "example": "Original Mix", "description": "Version label for the track, such as remix, radio edit, instrumental, or acoustic version." }, "isrc_code": { "type": "string", "example": "GBSMU2600001", "description": "ISRC assigned to the track, or blank when one should be assigned later." }, "iswc_code": { "type": "string", "example": "T0345246801", "description": "ISWC for the composition when available." }, "is_available_separately": { "type": "boolean", "example": true, "description": "Whether the track can be distributed or sold separately from the release when supported by selected stores." }, "is_parental_advisory": { "type": "boolean", "example": false, "description": "Whether the track should be marked with an explicit or parental advisory flag." }, "license_holder_year": { "type": "integer", "example": 2026, "description": "Year associated with the rights holder for the release or track metadata." }, "license_holder_name": { "type": "string", "example": "Night Shift Records Ltd", "description": "Legal name of the person or company that holds the relevant rights for the release or track." }, "playback_url": { "type": "string", "example": "https://media.spacemedia-docs.invalid/audio/midnight-atlas/master.wav", "format": "uri", "description": "Public URL returned for this resource or action." }, "preview_url": { "type": "string", "example": "https://media.spacemedia-docs.invalid/audio/midnight-atlas/preview.mp3", "format": "uri", "description": "Public URL returned for this resource or action." }, "documents_requested": { "type": "boolean", "example": false, "description": "Whether the track currently requires supporting rights or copyright documentation before review can continue." }, "created_at": { "type": "string", "example": "2026-07-04T09:30:00+00:00", "format": "date-time", "description": "Timestamp for when created occurred, formatted as ISO 8601 when available." }, "updated_at": { "type": "string", "example": "2026-07-04T10:15:00+00:00", "format": "date-time", "description": "Timestamp for when updated occurred, formatted as ISO 8601 when available." } }, "description": "Primary response payload for this request." } }, "required": [ "success", "message", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **404**: Resource not found. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### POST /api/v1/tracks/{track_id}/document Operation: `submitTrackDocument` Submit Track Document Upload a supporting document for a track, such as copyright, license, or claim material. Send the file as multipart form data and keep the returned document reference for follow-up support. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `track_id` in path (string, required): Public track reference returned by the API. #### Request body Multipart request payload. Required. **multipart/form-data** ```json { "type": "object", "additionalProperties": true, "properties": { "document": { "type": "string", "description": "Binary file upload for this endpoint.", "format": "binary" }, "notes": { "type": "string", "example": "License agreement for the vocal sample.", "description": "Operational notes visible to permitted organization users during review." } }, "required": [ "document" ] } ``` #### Responses - **200**: Submit Track Document succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "Document submitted.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." }, "data": { "type": "object", "additionalProperties": true, "properties": { "document_id": { "type": "string", "example": "a211d645-b1c8-43f7-8c7e-1b40adc2cc7c", "format": "uuid", "description": "Stable public document reference. Use this value in related endpoint paths and request bodies." }, "track_id": { "type": "string", "example": "e454b6f8-df5b-49db-9b9f-916f74ec1f21", "format": "uuid", "description": "Stable public track reference. Use this value in related endpoint paths and request bodies." }, "status": { "type": "string", "example": "submitted", "description": "Current lifecycle status for this record." } }, "description": "Primary response payload for this request." } }, "required": [ "success", "message", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **404**: Resource not found. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **422**: Validation failed for document. The request was not applied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### POST /api/v1/tracks/{track_id}/unassign/{release_id} Operation: `removeTrackFromRelease` Remove Track from Release Detach a track from a release by track_id and release_id when the release state allows catalog edits. The track remains available for other permitted workflows. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `track_id` in path (string, required): Public track reference returned by the API. - `release_id` in path (string, required): Public release reference returned by the API. #### Responses - **200**: Remove Track from Release succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "Track removed from release.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." } }, "required": [ "success", "message" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **404**: Resource not found. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### POST /api/v1/tracks/upload Operation: `uploadTrackAudio` Upload Track Audio Upload a complete audio file and receive an audio_file_id. Use that reference when creating or replacing a track, and reserve track_id for the stable track created later. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - Reference: `#/components/parameters/ActingUser` #### Request body Multipart request payload. Required. **multipart/form-data** ```json { "type": "object", "additionalProperties": true, "properties": { "track": { "type": "string", "description": "Binary file upload for this endpoint.", "format": "binary" } }, "required": [ "track" ] } ``` #### Responses - **200**: Upload Track Audio succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": false, "properties": { "success": { "type": "boolean", "const": true }, "audio_file_id": { "type": "string", "example": "audio_1783157400_6f9c2b8e4d1a", "description": "Temporary audio upload reference returned by the upload endpoint." }, "file_name": { "type": "string", "example": "midnight-atlas.wav", "description": "Stored file name for the uploaded audio." }, "original": { "type": "string", "example": "midnight-atlas-master.wav", "description": "Original client-provided file name." }, "links": { "type": "array", "items": { "type": "string", "format": "uri" }, "description": "Audio delivery URLs prepared for the uploaded file." }, "extensions": { "type": "object", "additionalProperties": false, "required": [ "input", "output" ], "properties": { "input": { "type": "string", "description": "Original audio format detected during upload." }, "output": { "type": "string", "description": "Playback or storage format prepared by the media pipeline." } } }, "duration": { "type": [ "integer", "null" ], "minimum": 0 }, "mime_type": { "type": [ "string", "null" ] }, "checksum": { "type": [ "string", "null" ] } }, "required": [ "success", "audio_file_id", "file_name", "original", "links", "extensions", "duration", "mime_type", "checksum" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **422**: Validation failed for track. The request was not applied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### POST /api/v1/tracks/upload/chunk Operation: `uploadTrackAudioChunk` Upload Track Audio Chunk Upload one chunk of a larger audio file using a stable upload_session_id, chunk_index, and total_chunks. After all chunks are accepted, use the returned audio_file_id in track metadata calls. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - Reference: `#/components/parameters/ActingUser` #### Request body Multipart request payload. Required. **multipart/form-data** ```json { "type": "object", "additionalProperties": true, "properties": { "upload_session_id": { "type": "string", "pattern": "^[A-Za-z0-9_-]{1,80}$", "example": "upload_midnight_atlas_20260704", "description": "Stable client-generated upload session reference. Reuse it for every chunk and status check." }, "chunk_index": { "type": "integer", "example": 3, "description": "Zero-based sequence number for this uploaded chunk within the upload session. The first chunk is 0." }, "total_chunks": { "type": "integer", "minimum": 1, "maximum": 64, "example": 8, "description": "Total number of chunks expected for the upload session." }, "file_name": { "type": "string", "maxLength": 255, "example": "midnight-atlas-master.wav", "description": "Original audio file name, including a supported extension." }, "file_size": { "type": "integer", "minimum": 1, "maximum": 524288000, "example": 83886080, "description": "Total size of the complete audio file in bytes." }, "chunk": { "type": "string", "description": "Binary chunk for a multipart audio upload session.", "format": "binary" } }, "required": [ "chunk_index", "total_chunks", "file_name", "file_size", "chunk" ] } ``` #### Responses - **200**: Upload Track Audio Chunk succeeded and returns the documented response body. **application/json** ```json { "$ref": "#/components/schemas/TrackUploadStatus" } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **422**: Validation failed for the chunk metadata or uploaded file. The request was not applied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### GET /api/v1/tracks/upload/{upload_session_id} Operation: `getTrackUploadStatus` Get Track Upload Status Recover the current state of a chunked audio upload after a retry, timeout, or lost final response. The result is scoped to the authenticated user and organization. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - Reference: `#/components/parameters/ActingUser` - `upload_session_id` in path (string, required): The upload_session_id originally sent with the chunked upload. #### Responses - **200**: The upload session exists and its current state is returned. **application/json** ```json { "$ref": "#/components/schemas/TrackUploadStatus" } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **404**: No active or recently completed upload session exists for this user and organization. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **422**: The upload session reference is malformed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### GET /api/v1/tracks/{track_id}/document/download Operation: `downloadTrackDocument` Download Track Document Generate a temporary download URL for the supporting document attached to a visible track. The track must belong to the organization and the caller must be allowed to view it. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `track_id` in path (string, required): Public track reference returned by track list, create, or release track endpoints. #### Responses - **200**: Download URL created. **application/json** ```json { "type": "object", "additionalProperties": false, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "File download link generated successfully.", "description": "Human-readable outcome suitable for logs and operator interfaces." }, "document_url": { "type": "string", "format": "uri", "example": "https://assets.spacemedia-docs.invalid/documents/midnight-atlas/rights-declaration.pdf", "description": "Temporary or public URL where the document can be downloaded." } }, "required": [ "success", "message" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **404**: Track or document not found. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ## Revenue Splits Create, update, list, and confirm revenue splits using public user and catalog references. ### GET /api/v1/splits Operation: `listRevenueSplits` List Revenue Splits List Revenue Splits. Use it to assign beneficiary shares to releases or tracks, invite collaborators, and manage split confirmation without exposing private accounting records. It returns public references and organization-visible fields only, so clients can safely use returned values in follow-up API calls. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `search` in query (string): Search term for matching visible records. - `page` in query (integer): Page number to return. - `size` in query (integer): Number of records per page. - `sort` in query (string): Sort direction for creation date. - `X-User-Id` in header (string): Optional user_id to perform an allowed action for a user in the same organization. #### Responses - **200**: List Revenue Splits succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "data": { "type": "array", "items": { "type": "object", "additionalProperties": true, "properties": { "split_id": { "type": "string", "example": "8df80f4e-63df-4562-87e8-f1b2f2f0ce47", "format": "uuid", "description": "Stable public split reference. Use this value in related endpoint paths and request bodies." }, "title": { "type": "string", "example": "Midnight Atlas Producer Share", "description": "Catalog or content title shown in the dashboard and API responses." }, "percentage": { "type": "integer", "example": 25, "description": "Revenue split percentage assigned to this beneficiary." }, "start_date": { "type": "string", "example": "2026-08-21", "format": "date", "description": "Calendar date for start." }, "end_date": { "description": "Calendar date for end.", "type": [ "string", "null" ], "format": "date" }, "locked": { "type": "boolean", "example": false, "description": "Whether the split, role, or configuration is locked from further editing in its current state." }, "beneficiary": { "type": "object", "additionalProperties": true, "properties": { "user_id": { "type": "string", "example": "43cda1b2-f7e9-49c7-b4fb-4fcfc5a02a9c", "format": "uuid", "description": "Stable public user reference. Use this value in related endpoint paths and request bodies." }, "name": { "type": "string", "example": "Eli Brooks", "description": "Display name for this beneficiary." }, "email": { "type": "string", "example": "eli.brooks@northstar-distribution.co.uk", "description": "Email address associated with the account, member, invitation, or beneficiary." } }, "description": "User or collaborator receiving the revenue split share." }, "creator": { "type": "object", "additionalProperties": true, "properties": { "user_id": { "type": "string", "example": "7d2d9f72-c0a2-4d4b-9b6d-7caa942b8a71", "format": "uuid", "description": "Stable public user reference. Use this value in related endpoint paths and request bodies." }, "name": { "type": "string", "example": "Maya Chen", "description": "Display name for this creator." }, "email": { "type": "string", "example": "maya.chen@northstar-distribution.co.uk", "description": "Email address associated with the account, member, invitation, or beneficiary." } }, "description": "User summary for the person who created the record." }, "releases": { "type": "array", "items": { "type": "object", "additionalProperties": true, "properties": { "release_id": { "type": "string", "example": "b7a15d95-58f6-4f67-b5d1-89f4f5bfb4d8", "format": "uuid", "description": "Stable public release reference. Use this value in related endpoint paths and request bodies." }, "title": { "type": "string", "example": "Midnight Atlas", "description": "Catalog or content title shown in the dashboard and API responses." }, "status": { "type": "string", "example": "draft", "description": "Current lifecycle status for this record." } } }, "description": "Releases visible for the current organization and permission scope." }, "tracks": { "type": "array", "items": { "type": "object", "additionalProperties": true, "properties": { "track_id": { "type": "string", "example": "e454b6f8-df5b-49db-9b9f-916f74ec1f21", "format": "uuid", "description": "Stable public track reference. Use this value in related endpoint paths and request bodies." }, "title": { "type": "string", "example": "Midnight Atlas", "description": "Catalog or content title shown in the dashboard and API responses." } } }, "description": "Tracks included in the release or returned by the catalog query." } } }, "description": "Primary response payload for this request." }, "meta": { "type": "object", "additionalProperties": true, "properties": { "current_page": { "type": "integer", "example": 1, "description": "current page for meta." }, "last_page": { "type": "integer", "example": 1, "description": "last page for meta." }, "per_page": { "type": "integer", "example": 20, "description": "per page for meta." }, "total": { "type": "integer", "example": 1, "description": "Total number of records matching the current filters." }, "from": { "type": "integer", "example": 1, "description": "from for meta." }, "to": { "type": "integer", "example": 1, "description": "to for meta." } }, "description": "Pagination, filter, or response metadata for this request." } }, "required": [ "success", "data", "meta" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **422**: Validation failed for search. The request was not applied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### POST /api/v1/splits Operation: `createRevenueSplit` Create Revenue Split Create a revenue split by assigning a beneficiary, percentage, dates, and release or track references. Use beneficiary_id for an existing organization user, beneficiary_email for an existing user by email, or email to invite a new beneficiary. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `X-User-Id` in header (string, required): Required user_id for catalog ownership and quota context. The client must also have users:act-as. #### Request body Request payload. Required. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "title": { "type": "string", "example": "Midnight Atlas Producer Share", "description": "Catalog or content title shown in the dashboard and API responses." }, "beneficiary_id": { "type": "string", "example": "43cda1b2-f7e9-49c7-b4fb-4fcfc5a02a9c", "format": "uuid", "description": "Public user reference for an existing organization user who should receive this split." }, "percentage": { "type": "integer", "example": 25, "description": "Revenue split percentage assigned to this beneficiary." }, "start_date": { "type": "string", "example": "2026-08-21", "format": "date", "description": "Calendar date for start." }, "release_ids": { "type": "array", "items": { "type": "string", "example": "b7a15d95-58f6-4f67-b5d1-89f4f5bfb4d8", "format": "uuid" }, "description": "Public release references used to assign a split or filter a workflow to organization-visible releases." }, "track_ids": { "type": "array", "items": { "type": "string", "example": "e454b6f8-df5b-49db-9b9f-916f74ec1f21", "format": "uuid" }, "description": "Ordered public track references used to assign, reorder, or split revenue for tracks visible to the organization." }, "beneficiary_email": { "type": "string", "format": "email", "example": "eli.brooks@northstar-distribution.co.uk", "description": "Email address of an existing organization user who should receive this split." }, "email": { "type": "string", "format": "email", "example": "riley.stone@northstar-distribution.co.uk", "description": "Email address to invite as a new split beneficiary when the person is not yet an organization user." } }, "required": [ "title", "percentage" ], "oneOf": [ { "required": [ "beneficiary_id" ] }, { "required": [ "beneficiary_email" ] }, { "required": [ "email" ] } ] } ``` #### Responses - **200**: Create Revenue Split succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "Revenue split created.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." }, "data": { "type": "object", "additionalProperties": true, "properties": { "split_id": { "type": "string", "example": "8df80f4e-63df-4562-87e8-f1b2f2f0ce47", "format": "uuid", "description": "Stable public split reference. Use this value in related endpoint paths and request bodies." }, "title": { "type": "string", "example": "Midnight Atlas Producer Share", "description": "Catalog or content title shown in the dashboard and API responses." }, "percentage": { "type": "integer", "example": 25, "description": "Revenue split percentage assigned to this beneficiary." }, "start_date": { "type": "string", "example": "2026-08-21", "format": "date", "description": "Calendar date for start." }, "end_date": { "description": "Calendar date for end.", "type": [ "string", "null" ], "format": "date" }, "locked": { "type": "boolean", "example": false, "description": "Whether the split, role, or configuration is locked from further editing in its current state." }, "beneficiary": { "type": "object", "additionalProperties": true, "properties": { "user_id": { "type": "string", "example": "43cda1b2-f7e9-49c7-b4fb-4fcfc5a02a9c", "format": "uuid", "description": "Stable public user reference. Use this value in related endpoint paths and request bodies." }, "name": { "type": "string", "example": "Eli Brooks", "description": "Display name for this beneficiary." }, "email": { "type": "string", "example": "eli.brooks@northstar-distribution.co.uk", "description": "Email address associated with the account, member, invitation, or beneficiary." } }, "description": "User or collaborator receiving the revenue split share." }, "creator": { "type": "object", "additionalProperties": true, "properties": { "user_id": { "type": "string", "example": "7d2d9f72-c0a2-4d4b-9b6d-7caa942b8a71", "format": "uuid", "description": "Stable public user reference. Use this value in related endpoint paths and request bodies." }, "name": { "type": "string", "example": "Maya Chen", "description": "Display name for this creator." }, "email": { "type": "string", "example": "maya.chen@northstar-distribution.co.uk", "description": "Email address associated with the account, member, invitation, or beneficiary." } }, "description": "User summary for the person who created the record." }, "releases": { "type": "array", "items": { "type": "object", "additionalProperties": true, "properties": { "release_id": { "type": "string", "example": "b7a15d95-58f6-4f67-b5d1-89f4f5bfb4d8", "format": "uuid", "description": "Stable public release reference. Use this value in related endpoint paths and request bodies." }, "title": { "type": "string", "example": "Midnight Atlas", "description": "Catalog or content title shown in the dashboard and API responses." }, "status": { "type": "string", "example": "draft", "description": "Current lifecycle status for this record." } } }, "description": "Releases visible for the current organization and permission scope." }, "tracks": { "type": "array", "items": { "type": "object", "additionalProperties": true, "properties": { "track_id": { "type": "string", "example": "e454b6f8-df5b-49db-9b9f-916f74ec1f21", "format": "uuid", "description": "Stable public track reference. Use this value in related endpoint paths and request bodies." }, "title": { "type": "string", "example": "Midnight Atlas", "description": "Catalog or content title shown in the dashboard and API responses." } } }, "description": "Tracks included in the release or returned by the catalog query." } }, "description": "Primary response payload for this request." } }, "required": [ "success", "message", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **422**: Validation failed for percentage. The request was not applied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### POST /api/v1/splits/{split_id} Operation: `updateRevenueSplit` Update Revenue Split Update a revenue split by split_id, including percentage, date, and release assignment changes that are allowed by the split state. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `split_id` in path (string, required): Public split reference returned by the API. #### Request body Request payload. Required. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "title": { "type": "string", "example": "Midnight Atlas Producer Share", "description": "Catalog or content title shown in the dashboard and API responses." }, "percentage": { "type": "integer", "example": 30, "description": "Revenue split percentage assigned to this beneficiary." }, "start_date": { "type": "string", "example": "2026-08-21", "format": "date", "description": "Calendar date for start." }, "release_ids": { "type": "array", "items": { "type": "string", "example": "b7a15d95-58f6-4f67-b5d1-89f4f5bfb4d8", "format": "uuid" }, "description": "Public release references used to assign a split or filter a workflow to organization-visible releases." } }, "required": [ "title", "percentage" ] } ``` #### Responses - **200**: Update Revenue Split succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "Revenue split updated.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." }, "data": { "type": "object", "additionalProperties": true, "properties": { "split_id": { "type": "string", "example": "8df80f4e-63df-4562-87e8-f1b2f2f0ce47", "format": "uuid", "description": "Stable public split reference. Use this value in related endpoint paths and request bodies." }, "title": { "type": "string", "example": "Midnight Atlas Producer Share", "description": "Catalog or content title shown in the dashboard and API responses." }, "percentage": { "type": "integer", "example": 30, "description": "Revenue split percentage assigned to this beneficiary." }, "start_date": { "type": "string", "example": "2026-08-21", "format": "date", "description": "Calendar date for start." }, "end_date": { "description": "Calendar date for end.", "type": [ "string", "null" ], "format": "date" }, "locked": { "type": "boolean", "example": false, "description": "Whether the split, role, or configuration is locked from further editing in its current state." }, "beneficiary": { "type": "object", "additionalProperties": true, "properties": { "user_id": { "type": "string", "example": "43cda1b2-f7e9-49c7-b4fb-4fcfc5a02a9c", "format": "uuid", "description": "Stable public user reference. Use this value in related endpoint paths and request bodies." }, "name": { "type": "string", "example": "Eli Brooks", "description": "Display name for this beneficiary." }, "email": { "type": "string", "example": "eli.brooks@northstar-distribution.co.uk", "description": "Email address associated with the account, member, invitation, or beneficiary." } }, "description": "User or collaborator receiving the revenue split share." }, "creator": { "type": "object", "additionalProperties": true, "properties": { "user_id": { "type": "string", "example": "7d2d9f72-c0a2-4d4b-9b6d-7caa942b8a71", "format": "uuid", "description": "Stable public user reference. Use this value in related endpoint paths and request bodies." }, "name": { "type": "string", "example": "Maya Chen", "description": "Display name for this creator." }, "email": { "type": "string", "example": "maya.chen@northstar-distribution.co.uk", "description": "Email address associated with the account, member, invitation, or beneficiary." } }, "description": "User summary for the person who created the record." }, "releases": { "type": "array", "items": { "type": "object", "additionalProperties": true, "properties": { "release_id": { "type": "string", "example": "b7a15d95-58f6-4f67-b5d1-89f4f5bfb4d8", "format": "uuid", "description": "Stable public release reference. Use this value in related endpoint paths and request bodies." }, "title": { "type": "string", "example": "Midnight Atlas", "description": "Catalog or content title shown in the dashboard and API responses." }, "status": { "type": "string", "example": "draft", "description": "Current lifecycle status for this record." } } }, "description": "Releases visible for the current organization and permission scope." }, "tracks": { "type": "array", "items": { "type": "object", "additionalProperties": true, "properties": { "track_id": { "type": "string", "example": "e454b6f8-df5b-49db-9b9f-916f74ec1f21", "format": "uuid", "description": "Stable public track reference. Use this value in related endpoint paths and request bodies." }, "title": { "type": "string", "example": "Midnight Atlas", "description": "Catalog or content title shown in the dashboard and API responses." } } }, "description": "Tracks included in the release or returned by the catalog query." } }, "description": "Primary response payload for this request." } }, "required": [ "success", "message", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **404**: Resource not found. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **422**: Validation failed for release_ids.0. The request was not applied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### POST /api/v1/splits/{split_id}/confirm Operation: `confirmRevenueSplit` Confirm Revenue Split Confirm participation in a revenue split by split_id. Use this when an invited or existing beneficiary accepts the split terms. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `split_id` in path (string, required): Public split reference returned by the API. #### Responses - **200**: Confirm Revenue Split succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "Revenue split confirmed.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." }, "data": { "type": "object", "additionalProperties": true, "properties": { "split_id": { "type": "string", "example": "8df80f4e-63df-4562-87e8-f1b2f2f0ce47", "format": "uuid", "description": "Stable public split reference. Use this value in related endpoint paths and request bodies." }, "confirmed": { "type": "boolean", "example": true, "description": "Whether the split, invitation, checkout, or action has been confirmed." }, "confirmed_at": { "type": "string", "example": "2026-07-04T10:15:00+00:00", "format": "date-time", "description": "Timestamp for when confirmed occurred, formatted as ISO 8601 when available." } }, "description": "Primary response payload for this request." } }, "required": [ "success", "message", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **404**: Resource not found. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ## Users Manage organization users and read their scoped artists, releases, tracks, revenue, and split records. ### GET /api/v1/users Operation: `listUsers` List Users List organization users with public user_id and role_id values. Use this endpoint before assigning catalog ownership, checking user access, or selecting an acted-for user for permitted API work. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `search` in query (string): Search term for matching visible records. - `page` in query (integer): Page number to return. - `size` in query (integer): Number of records per page. - `sort` in query (string): Sort direction for creation date. #### Responses - **200**: List Users succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "data": { "type": "array", "items": { "type": "object", "additionalProperties": true, "properties": { "user_id": { "type": "string", "example": "7d2d9f72-c0a2-4d4b-9b6d-7caa942b8a71", "format": "uuid", "description": "Stable public user reference. Use this value in related endpoint paths and request bodies." }, "name": { "type": "string", "example": "Maya Chen", "description": "Display name for this data." }, "full_name": { "type": "string", "example": "Maya Chen", "description": "Full display name assembled from the account profile fields." }, "first_name": { "type": "string", "example": "Maya", "description": "Given name for the user or member profile." }, "last_name": { "type": "string", "example": "Chen", "description": "Family name for the user or member profile." }, "email": { "type": "string", "example": "maya.chen@northstar-distribution.co.uk", "description": "Email address associated with the account, member, invitation, or beneficiary." }, "phone": { "type": "string", "example": "+442071838750", "description": "Phone number on the account profile when provided." }, "language": { "type": "string", "example": "en", "description": "Primary language value used for profile, release, or track metadata." }, "country": { "type": "string", "example": "United Kingdom", "description": "Country associated with the user, artist, or organization record." }, "profile_photo": { "type": "string", "example": "https://assets.spacemedia-docs.invalid/users/maya-chen/profile-photo.webp", "format": "uri", "description": "Public media URL or asset reference for the uploaded image." }, "verified": { "type": "boolean", "example": true, "description": "Whether the account email or identity state is verified." }, "email_verified_at": { "type": "string", "example": "2026-06-25T08:15:00+00:00", "format": "date-time", "description": "Timestamp for when email verified occurred, formatted as ISO 8601 when available." }, "last_login_at": { "type": "string", "example": "2026-07-04T10:15:00+00:00", "format": "date-time", "description": "Timestamp for when last login occurred, formatted as ISO 8601 when available." }, "invitation_status": { "type": "string", "example": "accepted", "description": "Invitation lifecycle status, such as pending or accepted." }, "is_invited": { "type": "boolean", "example": false, "description": "Whether this user was created through an organization invitation." }, "is_suspended": { "type": "boolean", "example": false, "description": "Whether organization access is currently suspended for this account." }, "roles": { "type": "array", "items": { "type": "object", "additionalProperties": true, "properties": { "role_id": { "type": "string", "example": "c0f1c68c-7c2f-4954-b52c-9d7e5eb46d3e", "format": "uuid", "description": "Stable public role reference. Use this value in related endpoint paths and request bodies." }, "name": { "type": "string", "example": "Catalog Manager", "description": "Display name for this roles." } } }, "description": "Roles assigned to the user or member within the organization." }, "organization_name": { "type": "string", "example": "Northstar Distribution", "description": "Display name of the organization that owns the record." }, "created_at": { "type": "string", "example": "2026-07-04T09:30:00+00:00", "format": "date-time", "description": "Timestamp for when created occurred, formatted as ISO 8601 when available." }, "updated_at": { "type": "string", "example": "2026-07-04T10:15:00+00:00", "format": "date-time", "description": "Timestamp for when updated occurred, formatted as ISO 8601 when available." } } }, "description": "Primary response payload for this request." }, "meta": { "type": "object", "additionalProperties": true, "properties": { "current_page": { "type": "integer", "example": 1, "description": "current page for meta." }, "last_page": { "type": "integer", "example": 1, "description": "last page for meta." }, "per_page": { "type": "integer", "example": 20, "description": "per page for meta." }, "total": { "type": "integer", "example": 1, "description": "Total number of records matching the current filters." }, "from": { "type": "integer", "example": 1, "description": "from for meta." }, "to": { "type": "integer", "example": 1, "description": "to for meta." } }, "description": "Pagination, filter, or response metadata for this request." } }, "required": [ "success", "data", "meta" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **422**: Validation failed for search. The request was not applied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### POST /api/v1/users Operation: `createUser` Create User Create an organization user with name, email, public role references, and optional invite delivery. Use role_ids from the role list returned by the users or member role endpoints, never numeric role values. Security: ```json [ { "BearerAuth": [] } ] ``` #### Request body Request payload. Required. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "first_name": { "type": "string", "example": "Eli", "description": "Given name for the user or member profile." }, "last_name": { "type": "string", "example": "Brooks", "description": "Family name for the user or member profile." }, "email": { "type": "string", "example": "eli.brooks@northstar-distribution.co.uk", "description": "Email address associated with the account, member, invitation, or beneficiary." }, "role_ids": { "type": "array", "items": { "type": "string", "example": "c0f1c68c-7c2f-4954-b52c-9d7e5eb46d3e", "format": "uuid" }, "description": "Public role references assigned to the user. Use values returned by role or member role endpoints, not numeric role values." } }, "required": [ "email", "role_ids" ] } ``` #### Responses - **201**: Create User created the resource and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "User invited.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." }, "data": { "type": "object", "additionalProperties": true, "properties": { "user_id": { "type": "string", "example": "43cda1b2-f7e9-49c7-b4fb-4fcfc5a02a9c", "format": "uuid", "description": "Stable public user reference. Use this value in related endpoint paths and request bodies." }, "email": { "type": "string", "example": "eli.brooks@northstar-distribution.co.uk", "description": "Email address associated with the account, member, invitation, or beneficiary." }, "invitation_status": { "type": "string", "example": "pending", "description": "Invitation lifecycle status, such as pending or accepted." }, "roles": { "type": "array", "items": { "type": "object", "additionalProperties": true, "properties": { "role_id": { "type": "string", "example": "c0f1c68c-7c2f-4954-b52c-9d7e5eb46d3e", "format": "uuid", "description": "Stable public role reference. Use this value in related endpoint paths and request bodies." }, "name": { "type": "string", "example": "Catalog Manager", "description": "Display name for this roles." } } }, "description": "Roles assigned to the user or member within the organization." } }, "description": "Primary response payload for this request." } }, "required": [ "success", "message", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **422**: Validation failed for first_name. The request was not applied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### POST /api/v1/users/{user_id} Operation: `updateUser` Update User Update an organization user profile or role assignment by user_id. Submit only public role_ids and profile fields that the acted-for user is allowed to change for that account. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `user_id` in path (string, required): Public user reference returned by the API. #### Request body Request payload. Required. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "first_name": { "type": "string", "example": "Eli", "description": "Given name for the user or member profile." }, "last_name": { "type": "string", "example": "Brooks", "description": "Family name for the user or member profile." }, "role_ids": { "type": "array", "items": { "type": "string", "example": "c0f1c68c-7c2f-4954-b52c-9d7e5eb46d3e", "format": "uuid" }, "description": "Public role references assigned to the user. Use values returned by role or member role endpoints, not numeric role values." }, "country": { "type": "string", "example": "United Kingdom", "description": "Country associated with the user, artist, or organization record." }, "language": { "type": "string", "example": "en", "description": "Primary language value used for profile, release, or track metadata." } }, "required": [ "first_name", "last_name", "role_ids" ] } ``` #### Responses - **200**: Update User succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "User updated successfully.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." } }, "required": [ "success", "message" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **404**: Resource not found. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **422**: Validation failed for first_name. The request was not applied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### GET /api/v1/users/{user_id}/artists Operation: `listUserArtists` List User Artists List artist profiles associated with a user inside the organization. Use the returned artist_id values when filtering catalog work or assigning credits. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `user_id` in path (string, required): Public user reference returned by the API. - `page` in query (integer): Page number to return. - `size` in query (integer): Number of records per page. #### Responses - **200**: List User Artists succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "data": { "type": "array", "items": { "type": "object", "additionalProperties": true, "properties": { "artist_id": { "type": "string", "example": "6f209ac7-d82c-4c8f-9d3e-bfe39c0df802", "format": "uuid", "description": "Stable public artist reference. Use this value in related endpoint paths and request bodies." }, "name": { "type": "string", "example": "Nova Vale", "description": "Display name for this data." }, "artist_type": { "type": "string", "example": "Primary Artist", "description": "Artist classification used for DSP metadata and credit display." }, "spotify_id": { "type": "string", "example": "3mY7kJqR8B2nQvP6LxT4Za", "description": "Optional external Spotify artist reference for matching catalog profiles. It is not a SpaceMedia API path reference; use artist_id for SpaceMedia API calls." }, "bio": { "type": "string", "example": "Electronic artist and producer from London.", "description": "Artist biography or descriptive profile text." }, "country": { "type": "string", "example": "GB", "description": "Country associated with the user, artist, or organization record." }, "releases_count": { "type": "integer", "example": 2, "description": "Number of releases currently associated with the artist." }, "tracks_count": { "type": "integer", "example": 7, "description": "Number of tracks currently associated with the artist." }, "total_streams": { "type": "integer", "example": 125000, "description": "Total reported streams when reporting data is available." }, "created_at": { "type": "string", "example": "2026-06-01T11:00:00+00:00", "format": "date-time", "description": "Timestamp for when created occurred, formatted as ISO 8601 when available." }, "updated_at": { "type": "string", "example": "2026-07-04T10:15:00+00:00", "format": "date-time", "description": "Timestamp for when updated occurred, formatted as ISO 8601 when available." } } }, "description": "Primary response payload for this request." }, "meta": { "type": "object", "additionalProperties": true, "properties": { "current_page": { "type": "integer", "example": 1, "description": "current page for meta." }, "last_page": { "type": "integer", "example": 1, "description": "last page for meta." }, "per_page": { "type": "integer", "example": 20, "description": "per page for meta." }, "total": { "type": "integer", "example": 1, "description": "Total number of records matching the current filters." }, "from": { "type": "integer", "example": 1, "description": "from for meta." }, "to": { "type": "integer", "example": 1, "description": "to for meta." } }, "description": "Pagination, filter, or response metadata for this request." } }, "required": [ "success", "data", "meta" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **404**: Resource not found. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **422**: Validation failed for page. The request was not applied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### GET /api/v1/users/{user_id}/detail Operation: `getOrganizationUser` Get Organization User Return one organization user profile, assigned roles, account state, and the organization display name by user_id. The response never exposes organization identifiers because authentication already scopes the organization. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `user_id` in path (string, required): Public user reference returned by the API. #### Responses - **200**: Get Organization User succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "data": { "type": "object", "additionalProperties": true, "properties": { "user_id": { "type": "string", "example": "7d2d9f72-c0a2-4d4b-9b6d-7caa942b8a71", "format": "uuid", "description": "Stable public user reference. Use this value in related endpoint paths and request bodies." }, "name": { "type": "string", "example": "Maya Chen", "description": "Display name for this data." }, "full_name": { "type": "string", "example": "Maya Chen", "description": "Full display name assembled from the account profile fields." }, "first_name": { "type": "string", "example": "Maya", "description": "Given name for the user or member profile." }, "last_name": { "type": "string", "example": "Chen", "description": "Family name for the user or member profile." }, "email": { "type": "string", "example": "maya.chen@northstar-distribution.co.uk", "description": "Email address associated with the account, member, invitation, or beneficiary." }, "phone": { "type": "string", "example": "+442071838750", "description": "Phone number on the account profile when provided." }, "language": { "type": "string", "example": "en", "description": "Primary language value used for profile, release, or track metadata." }, "country": { "type": "string", "example": "United Kingdom", "description": "Country associated with the user, artist, or organization record." }, "profile_photo": { "type": "string", "example": "https://assets.spacemedia-docs.invalid/users/maya-chen/profile-photo.webp", "format": "uri", "description": "Public media URL or asset reference for the uploaded image." }, "verified": { "type": "boolean", "example": true, "description": "Whether the account email or identity state is verified." }, "email_verified_at": { "type": "string", "example": "2026-06-25T08:15:00+00:00", "format": "date-time", "description": "Timestamp for when email verified occurred, formatted as ISO 8601 when available." }, "last_login_at": { "type": "string", "example": "2026-07-04T10:15:00+00:00", "format": "date-time", "description": "Timestamp for when last login occurred, formatted as ISO 8601 when available." }, "invitation_status": { "type": "string", "example": "accepted", "description": "Invitation lifecycle status, such as pending or accepted." }, "is_invited": { "type": "boolean", "example": false, "description": "Whether this user was created through an organization invitation." }, "is_suspended": { "type": "boolean", "example": false, "description": "Whether organization access is currently suspended for this account." }, "roles": { "type": "array", "items": { "type": "object", "additionalProperties": true, "properties": { "role_id": { "type": "string", "example": "c0f1c68c-7c2f-4954-b52c-9d7e5eb46d3e", "format": "uuid", "description": "Stable public role reference. Use this value in related endpoint paths and request bodies." }, "name": { "type": "string", "example": "Catalog Manager", "description": "Display name for this roles." } } }, "description": "Roles assigned to the user or member within the organization." }, "organization_name": { "type": "string", "example": "Northstar Distribution", "description": "Display name of the organization that owns the record." }, "created_at": { "type": "string", "example": "2026-07-04T09:30:00+00:00", "format": "date-time", "description": "Timestamp for when created occurred, formatted as ISO 8601 when available." }, "updated_at": { "type": "string", "example": "2026-07-04T10:15:00+00:00", "format": "date-time", "description": "Timestamp for when updated occurred, formatted as ISO 8601 when available." } }, "description": "Primary response payload for this request." } }, "required": [ "success", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **404**: Resource not found. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### POST /api/v1/users/{user_id}/profile-photo Operation: `updateUserProfilePhoto` Update User Profile Photo Upload a replacement profile photo for an organization user by user_id. Send the image as multipart form data and use the returned user profile for subsequent display or audit purposes. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `user_id` in path (string, required): Public user reference returned by the API. #### Request body Multipart request payload. Required. **multipart/form-data** ```json { "type": "object", "additionalProperties": false, "properties": { "profile_photo": { "type": "string", "description": "Binary profile image file for the user account.", "format": "binary" } }, "required": [ "profile_photo" ] } ``` #### Responses - **200**: Update User Profile Photo succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "Profile photo updated successfully.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." }, "data": { "type": "object", "additionalProperties": true, "properties": { "user_id": { "type": "string", "example": "43cda1b2-f7e9-49c7-b4fb-4fcfc5a02a9c", "format": "uuid", "description": "Stable public user reference. Use this value in related endpoint paths and request bodies." }, "profile_photo": { "type": "string", "example": "https://assets.spacemedia-docs.invalid/users/eli-brooks/profile-photo.webp", "format": "uri", "description": "Public media URL or asset reference for the uploaded image." }, "updated_at": { "type": "string", "example": "2026-07-04T10:15:00+00:00", "format": "date-time", "description": "Timestamp for when updated occurred, formatted as ISO 8601 when available." } }, "description": "Primary response payload for this request." } }, "required": [ "success", "message", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **404**: Resource not found. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **422**: Validation failed for profile_photo. The request was not applied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### GET /api/v1/users/{user_id}/releases Operation: `listUserReleases` List User Releases List releases associated with a user inside the organization. Use the returned release_id values for track, rights, review, and checkout follow-up calls. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `user_id` in path (string, required): Public user reference returned by the API. - `page` in query (integer): Page number to return. - `size` in query (integer): Number of records per page. #### Responses - **200**: List User Releases succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "data": { "type": "array", "items": { "type": "object", "additionalProperties": true, "properties": { "release_id": { "type": "string", "example": "b7a15d95-58f6-4f67-b5d1-89f4f5bfb4d8", "format": "uuid", "description": "Stable public release reference. Use this value in related endpoint paths and request bodies." }, "title": { "type": "string", "example": "Midnight Atlas", "description": "Catalog or content title shown in the dashboard and API responses." }, "status": { "type": "string", "example": "draft", "description": "Current lifecycle status for this record." }, "format": { "type": "string", "example": "single", "description": "Release format, such as single, EP, or album." }, "label": { "type": "string", "example": "Night Shift Records", "description": "Label name attached to the release metadata." }, "genre": { "type": "string", "example": "Electronic", "description": "Primary release or track genre selected from supported values." }, "secondary_genre": { "type": "string", "example": "Ambient", "description": "Optional secondary genre used for more precise metadata." }, "language": { "type": "string", "example": "English", "description": "Primary language value used for profile, release, or track metadata." }, "explicit_content": { "type": "boolean", "example": false, "description": "Whether the release or track is marked as explicit." }, "upc_code": { "type": "string", "example": "5054429191012", "description": "UPC assigned to the release, or null when it has not been assigned yet." }, "reference_number": { "type": "string", "example": "NSD-2026-041", "description": "Human-readable catalog or billing reference shown in the dashboard." }, "scheduled_date": { "type": "string", "example": "2026-08-21", "format": "date", "description": "Scheduled release date used for delivery planning and catalog display." }, "original_release_date": { "type": "string", "example": "2026-08-21", "format": "date", "description": "Calendar date for original release." }, "copyright_detection_enabled": { "type": "boolean", "example": true, "description": "Whether copyright checking is enabled for the organization or release workflow." }, "price_category": { "type": "string", "example": "mid", "description": "Release price tier or commercial category used for store delivery and billing decisions." }, "territories": { "type": "array", "items": { "type": "string", "example": "GB" }, "description": "Territory codes where the release or rights metadata should apply." }, "distribution": { "type": "array", "items": { "type": "object", "additionalProperties": true, "properties": { "channel": { "type": "string", "example": "spotify", "description": "Delivery channel or store identifier using public snake_case values." }, "status": { "type": "string", "example": "selected", "description": "Current lifecycle status for this record." } } }, "description": "Delivery destinations and their organization-visible status values." }, "cover_art": { "type": "string", "example": "https://assets.spacemedia-docs.invalid/releases/midnight-atlas/cover.jpg", "format": "uri", "description": "Public media URL or asset reference for the uploaded image." }, "track_count": { "type": "integer", "example": 1, "description": "Number of track records visible in this context." }, "artists": { "type": "array", "items": { "type": "object", "additionalProperties": false, "properties": { "artist_id": { "type": "string", "example": "6f209ac7-d82c-4c8f-9d3e-bfe39c0df802", "format": "uuid", "description": "Public artist reference returned by the artists API." }, "name": { "type": "string", "example": "Nova Vale", "description": "Display name for this artists." }, "type": { "type": "string", "example": "Primary Artist", "description": "Artist credit role for this release or track, such as Primary Artist or Featured Artist." } }, "required": [ "artist_id", "type" ] }, "description": "Artists credited or attached to this catalog record." }, "created_by": { "type": "object", "additionalProperties": true, "properties": { "user_id": { "type": "string", "example": "7d2d9f72-c0a2-4d4b-9b6d-7caa942b8a71", "format": "uuid", "description": "Stable public user reference. Use this value in related endpoint paths and request bodies." }, "name": { "type": "string", "example": "Maya Chen", "description": "Display name for this created_by." }, "email": { "type": "string", "example": "maya.chen@northstar-distribution.co.uk", "description": "Email address associated with the account, member, invitation, or beneficiary." } }, "description": "User that created the record when available to the current organization." }, "created_at": { "type": "string", "example": "2026-07-04T09:30:00+00:00", "format": "date-time", "description": "Timestamp for when created occurred, formatted as ISO 8601 when available." }, "updated_at": { "type": "string", "example": "2026-07-04T10:15:00+00:00", "format": "date-time", "description": "Timestamp for when updated occurred, formatted as ISO 8601 when available." } } }, "description": "Primary response payload for this request." }, "meta": { "type": "object", "additionalProperties": true, "properties": { "current_page": { "type": "integer", "example": 1, "description": "current page for meta." }, "last_page": { "type": "integer", "example": 1, "description": "last page for meta." }, "per_page": { "type": "integer", "example": 20, "description": "per page for meta." }, "total": { "type": "integer", "example": 1, "description": "Total number of records matching the current filters." }, "from": { "type": "integer", "example": 1, "description": "from for meta." }, "to": { "type": "integer", "example": 1, "description": "to for meta." } }, "description": "Pagination, filter, or response metadata for this request." } }, "required": [ "success", "data", "meta" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **404**: Resource not found. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **422**: Validation failed for page. The request was not applied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### GET /api/v1/users/{user_id}/revenue Operation: `listUserRevenue` List User Revenue List revenue records visible for a user. The response uses release_id and track_id references so clients can connect revenue back to catalog metadata. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `user_id` in path (string, required): Public user reference returned by the API. - `page` in query (integer): Page number to return. - `size` in query (integer): Number of records per page. #### Responses - **200**: List User Revenue succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "data": { "type": "array", "items": { "type": "object", "additionalProperties": true, "properties": { "revenue_record_id": { "type": "string", "example": "rev_midnight_atlas_june_2026", "description": "Stable public revenue record reference. Use this value in related endpoint paths and request bodies." }, "release": { "type": "object", "additionalProperties": true, "properties": { "release_id": { "type": "string", "example": "b7a15d95-58f6-4f67-b5d1-89f4f5bfb4d8", "format": "uuid", "description": "Stable public release reference. Use this value in related endpoint paths and request bodies." }, "title": { "type": "string", "example": "Midnight Atlas", "description": "Catalog or content title shown in the dashboard and API responses." }, "status": { "type": "string", "example": "draft", "description": "Current lifecycle status for this record." } }, "description": "Release summary or nested release object connected to this workflow." }, "track": { "type": "object", "additionalProperties": true, "properties": { "track_id": { "type": "string", "example": "e454b6f8-df5b-49db-9b9f-916f74ec1f21", "format": "uuid", "description": "Stable public track reference. Use this value in related endpoint paths and request bodies." }, "title": { "type": "string", "example": "Midnight Atlas", "description": "Catalog or content title shown in the dashboard and API responses." } }, "description": "Track summary connected to the release, split, document, or revenue item." }, "store": { "type": "string", "example": "Spotify", "description": "DSP, storefront, or destination where the release, track, or smartlink is available." }, "country": { "type": "string", "example": "GB", "description": "Country associated with the user, artist, or organization record." }, "month": { "type": "string", "example": "2026-06", "description": "Calendar month represented by the reporting or revenue entry." }, "revenue": { "type": "number", "example": 128.42, "description": "Revenue amount, trend, or summary visible to the organization." }, "currency": { "type": "string", "example": "GBP", "description": "ISO currency code for the amount shown on the same object." } } }, "description": "Primary response payload for this request." }, "meta": { "type": "object", "additionalProperties": true, "properties": { "current_page": { "type": "integer", "example": 1, "description": "current page for meta." }, "last_page": { "type": "integer", "example": 1, "description": "last page for meta." }, "per_page": { "type": "integer", "example": 20, "description": "per page for meta." }, "total": { "type": "integer", "example": 1, "description": "Total number of records matching the current filters." }, "from": { "type": "integer", "example": 1, "description": "from for meta." }, "to": { "type": "integer", "example": 1, "description": "to for meta." } }, "description": "Pagination, filter, or response metadata for this request." } }, "required": [ "success", "data", "meta" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **404**: Resource not found. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **422**: Validation failed for page. The request was not applied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### GET /api/v1/users/{user_id}/splits Operation: `listUserSplits` List User Revenue Splits List revenue splits where the user is creator or beneficiary. Use split_id values to inspect, update, or confirm split participation. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `user_id` in path (string, required): Public user reference returned by the API. - `page` in query (integer): Page number to return. - `size` in query (integer): Number of records per page. #### Responses - **200**: List User Revenue Splits succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "data": { "type": "array", "items": { "type": "object", "additionalProperties": true, "properties": { "split_id": { "type": "string", "example": "8df80f4e-63df-4562-87e8-f1b2f2f0ce47", "format": "uuid", "description": "Stable public split reference. Use this value in related endpoint paths and request bodies." }, "title": { "type": "string", "example": "Midnight Atlas Producer Share", "description": "Catalog or content title shown in the dashboard and API responses." }, "percentage": { "type": "integer", "example": 25, "description": "Revenue split percentage assigned to this beneficiary." }, "start_date": { "type": "string", "example": "2026-08-21", "format": "date", "description": "Calendar date for start." }, "end_date": { "description": "Calendar date for end.", "type": [ "string", "null" ], "format": "date" }, "locked": { "type": "boolean", "example": false, "description": "Whether the split, role, or configuration is locked from further editing in its current state." }, "beneficiary": { "type": "object", "additionalProperties": true, "properties": { "user_id": { "type": "string", "example": "43cda1b2-f7e9-49c7-b4fb-4fcfc5a02a9c", "format": "uuid", "description": "Stable public user reference. Use this value in related endpoint paths and request bodies." }, "name": { "type": "string", "example": "Eli Brooks", "description": "Display name for this beneficiary." }, "email": { "type": "string", "example": "eli.brooks@northstar-distribution.co.uk", "description": "Email address associated with the account, member, invitation, or beneficiary." } }, "description": "User or collaborator receiving the revenue split share." }, "creator": { "type": "object", "additionalProperties": true, "properties": { "user_id": { "type": "string", "example": "7d2d9f72-c0a2-4d4b-9b6d-7caa942b8a71", "format": "uuid", "description": "Stable public user reference. Use this value in related endpoint paths and request bodies." }, "name": { "type": "string", "example": "Maya Chen", "description": "Display name for this creator." }, "email": { "type": "string", "example": "maya.chen@northstar-distribution.co.uk", "description": "Email address associated with the account, member, invitation, or beneficiary." } }, "description": "User summary for the person who created the record." }, "releases": { "type": "array", "items": { "type": "object", "additionalProperties": true, "properties": { "release_id": { "type": "string", "example": "b7a15d95-58f6-4f67-b5d1-89f4f5bfb4d8", "format": "uuid", "description": "Stable public release reference. Use this value in related endpoint paths and request bodies." }, "title": { "type": "string", "example": "Midnight Atlas", "description": "Catalog or content title shown in the dashboard and API responses." }, "status": { "type": "string", "example": "draft", "description": "Current lifecycle status for this record." } } }, "description": "Releases visible for the current organization and permission scope." }, "tracks": { "type": "array", "items": { "type": "object", "additionalProperties": true, "properties": { "track_id": { "type": "string", "example": "e454b6f8-df5b-49db-9b9f-916f74ec1f21", "format": "uuid", "description": "Stable public track reference. Use this value in related endpoint paths and request bodies." }, "title": { "type": "string", "example": "Midnight Atlas", "description": "Catalog or content title shown in the dashboard and API responses." } } }, "description": "Tracks included in the release or returned by the catalog query." } } }, "description": "Primary response payload for this request." }, "meta": { "type": "object", "additionalProperties": true, "properties": { "current_page": { "type": "integer", "example": 1, "description": "current page for meta." }, "last_page": { "type": "integer", "example": 1, "description": "last page for meta." }, "per_page": { "type": "integer", "example": 20, "description": "per page for meta." }, "total": { "type": "integer", "example": 1, "description": "Total number of records matching the current filters." }, "from": { "type": "integer", "example": 1, "description": "from for meta." }, "to": { "type": "integer", "example": 1, "description": "to for meta." } }, "description": "Pagination, filter, or response metadata for this request." } }, "required": [ "success", "data", "meta" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **404**: Resource not found. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **422**: Validation failed for page. The request was not applied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### POST /api/v1/users/{user_id}/suspend Operation: `suspendUser` Suspend User Suspend an organization user by user_id when policy allows it. Use this to block future access without deleting catalog ownership or historical activity records. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `user_id` in path (string, required): Public user reference returned by the API. #### Responses - **200**: Suspend User succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "User suspended.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." } }, "required": [ "success", "message" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **404**: Resource not found. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### GET /api/v1/users/{user_id}/tracks Operation: `listUserTracks` List User Tracks List tracks associated with a user inside the organization. Use the returned track_id values for metadata edits, document uploads, and release assignment calls. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `user_id` in path (string, required): Public user reference returned by the API. - `page` in query (integer): Page number to return. - `size` in query (integer): Number of records per page. #### Responses - **200**: List User Tracks succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "data": { "type": "array", "items": { "type": "object", "additionalProperties": true, "properties": { "track_id": { "type": "string", "example": "e454b6f8-df5b-49db-9b9f-916f74ec1f21", "format": "uuid", "description": "Stable public track reference. Use this value in related endpoint paths and request bodies." }, "release": { "type": "object", "additionalProperties": true, "properties": { "release_id": { "type": "string", "example": "b7a15d95-58f6-4f67-b5d1-89f4f5bfb4d8", "format": "uuid", "description": "Stable public release reference. Use this value in related endpoint paths and request bodies." }, "title": { "type": "string", "example": "Midnight Atlas", "description": "Catalog or content title shown in the dashboard and API responses." }, "status": { "type": "string", "example": "draft", "description": "Current lifecycle status for this record." } }, "description": "Release summary or nested release object connected to this workflow." }, "title": { "type": "string", "example": "Midnight Atlas", "description": "Catalog or content title shown in the dashboard and API responses." }, "artists": { "type": "array", "items": { "type": "object", "additionalProperties": false, "properties": { "artist_id": { "type": "string", "example": "6f209ac7-d82c-4c8f-9d3e-bfe39c0df802", "format": "uuid", "description": "Public artist reference returned by the artists API." }, "name": { "type": "string", "example": "Nova Vale", "description": "Display name for this artists." }, "type": { "type": "string", "example": "Primary Artist", "description": "Artist credit role for this release or track, such as Primary Artist or Featured Artist." } }, "required": [ "artist_id", "type" ] }, "description": "Artists credited or attached to this catalog record." }, "duration": { "type": "integer", "example": 196, "description": "Track duration in seconds or a display-ready duration value." }, "language": { "type": "string", "example": "English", "description": "Primary language value used for profile, release, or track metadata." }, "primary_genre": { "type": "string", "example": "Electronic", "description": "Primary track genre selected from supported values." }, "secondary_genre": { "type": "string", "example": "Ambient", "description": "Optional secondary genre used for more precise metadata." }, "track_version": { "type": "string", "example": "Original Mix", "description": "Version label for the track, such as remix, radio edit, instrumental, or acoustic version." }, "isrc_code": { "type": "string", "example": "GBSMU2600001", "description": "ISRC assigned to the track, or blank when one should be assigned later." }, "iswc_code": { "type": "string", "example": "T0345246801", "description": "ISWC for the composition when available." }, "is_available_separately": { "type": "boolean", "example": true, "description": "Whether the track can be distributed or sold separately from the release when supported by selected stores." }, "is_parental_advisory": { "type": "boolean", "example": false, "description": "Whether the track should be marked with an explicit or parental advisory flag." }, "license_holder_year": { "type": "integer", "example": 2026, "description": "Year associated with the rights holder for the release or track metadata." }, "license_holder_name": { "type": "string", "example": "Night Shift Records Ltd", "description": "Legal name of the person or company that holds the relevant rights for the release or track." }, "playback_url": { "type": "string", "example": "https://media.spacemedia-docs.invalid/audio/midnight-atlas/master.wav", "format": "uri", "description": "Public URL returned for this resource or action." }, "preview_url": { "type": "string", "example": "https://media.spacemedia-docs.invalid/audio/midnight-atlas/preview.mp3", "format": "uri", "description": "Public URL returned for this resource or action." }, "documents_requested": { "type": "boolean", "example": false, "description": "Whether the track currently requires supporting rights or copyright documentation before review can continue." }, "created_at": { "type": "string", "example": "2026-07-04T09:30:00+00:00", "format": "date-time", "description": "Timestamp for when created occurred, formatted as ISO 8601 when available." }, "updated_at": { "type": "string", "example": "2026-07-04T10:15:00+00:00", "format": "date-time", "description": "Timestamp for when updated occurred, formatted as ISO 8601 when available." } } }, "description": "Primary response payload for this request." }, "meta": { "type": "object", "additionalProperties": true, "properties": { "current_page": { "type": "integer", "example": 1, "description": "current page for meta." }, "last_page": { "type": "integer", "example": 1, "description": "last page for meta." }, "per_page": { "type": "integer", "example": 20, "description": "per page for meta." }, "total": { "type": "integer", "example": 1, "description": "Total number of records matching the current filters." }, "from": { "type": "integer", "example": 1, "description": "from for meta." }, "to": { "type": "integer", "example": 1, "description": "to for meta." } }, "description": "Pagination, filter, or response metadata for this request." } }, "required": [ "success", "data", "meta" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **404**: Resource not found. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **422**: Validation failed for page. The request was not applied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### POST /api/v1/users/{user_id}/unsuspend Operation: `unsuspendUser` Unsuspend User Restore access for a suspended organization user by user_id. The response confirms the active account state and can be followed by a user detail lookup. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `user_id` in path (string, required): Public user reference returned by the API. #### Responses - **200**: Unsuspend User succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "User unsuspended.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." } }, "required": [ "success", "message" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **404**: Resource not found. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ## Plans and Upgrades Discover membership plans, pay-per-release options, and organization upgrade choices before checkout. ### GET /api/v1/packages Operation: `listMembershipPlans` List Membership Plans List Membership Plans. Use it to compare available subscription and pay-per-release plans before starting a checkout or changing the organization billing setup. It returns public references and organization-visible fields only, so clients can safely use returned values in follow-up API calls. Security: ```json [ { "BearerAuth": [] } ] ``` #### Responses - **200**: List Membership Plans succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "data": { "type": "array", "items": { "type": "object", "additionalProperties": true, "properties": { "package_id": { "type": "string", "example": "f3e184c8-8b3a-45b8-9bcb-cc12f70826b6", "format": "uuid", "description": "Stable public package reference. Use this value in related endpoint paths and request bodies." }, "name": { "type": "string", "example": "Growth Distribution Monthly", "description": "Display name for this data." }, "type": { "type": "string", "example": "membership", "description": "Public type or role value for this item." }, "status": { "type": "string", "example": "published", "description": "Current lifecycle status for this record." }, "price": { "type": "integer", "example": 49, "description": "Price for the package, plan, add-on, release order, or credit purchase in the response currency." }, "currency": { "type": "string", "example": "GBP", "description": "ISO currency code for the amount shown on the same object." }, "royalty_percentage": { "type": "integer", "example": 85, "description": "Royalty percentage associated with the package or pay-per-release plan." }, "artist_profile_limit": { "type": "integer", "example": 25, "description": "Maximum number of artist profiles included in the package or plan." }, "release_limit": { "type": "integer", "example": 50, "description": "Maximum number of releases included in the package or plan." }, "release_limit_cycle": { "type": "string", "example": "monthly", "description": "Period over which the release limit applies." }, "feature_list": { "type": "array", "items": { "type": "string", "example": "Unlimited team members" }, "description": "List of features included in the package, plan, or add-on." } } }, "description": "Primary response payload for this request." }, "meta": { "type": "object", "additionalProperties": true, "properties": { "current_page": { "type": "integer", "example": 1, "description": "current page for meta." }, "last_page": { "type": "integer", "example": 1, "description": "last page for meta." }, "per_page": { "type": "integer", "example": 20, "description": "per page for meta." }, "total": { "type": "integer", "example": 1, "description": "Total number of records matching the current filters." }, "from": { "type": "integer", "example": 1, "description": "from for meta." }, "to": { "type": "integer", "example": 1, "description": "to for meta." } }, "description": "Pagination, filter, or response metadata for this request." } }, "required": [ "success", "data", "meta" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### GET /api/v1/packages/pay-per-release Operation: `listPayPerReleasePlans` List Pay-Per-Release Plans List Pay-Per-Release Plans. Use it to compare available subscription and pay-per-release plans before starting a checkout or changing the organization billing setup. It returns public references and organization-visible fields only, so clients can safely use returned values in follow-up API calls. Security: ```json [ { "BearerAuth": [] } ] ``` #### Responses - **200**: List Pay-Per-Release Plans succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "data": { "type": "array", "items": { "type": "object", "additionalProperties": true, "properties": { "plan_id": { "type": "string", "example": "d93dfb89-27ef-4104-a609-4e6dbd272c37", "format": "uuid", "description": "Stable public plan reference. Use this value in related endpoint paths and request bodies." }, "name": { "type": "string", "example": "Single Release Credit", "description": "Display name for this data." }, "release_type": { "type": "string", "example": "single", "description": "Release type covered by the pay-per-release plan, such as single, EP, or album." }, "active": { "type": "boolean", "example": true, "description": "Whether the plan, add-on, or configuration is available for use." }, "price": { "type": "integer", "example": 9, "description": "Price for the package, plan, add-on, release order, or credit purchase in the response currency." }, "currency": { "type": "string", "example": "GBP", "description": "ISO currency code for the amount shown on the same object." }, "royalty_percentage": { "type": "integer", "example": 90, "description": "Royalty percentage associated with the package or pay-per-release plan." }, "feature_list": { "type": "array", "items": { "type": "string", "example": "One single release" }, "description": "List of features included in the package, plan, or add-on." } } }, "description": "Primary response payload for this request." }, "meta": { "type": "object", "additionalProperties": true, "properties": { "current_page": { "type": "integer", "example": 1, "description": "current page for meta." }, "last_page": { "type": "integer", "example": 1, "description": "last page for meta." }, "per_page": { "type": "integer", "example": 20, "description": "per page for meta." }, "total": { "type": "integer", "example": 1, "description": "Total number of records matching the current filters." }, "from": { "type": "integer", "example": 1, "description": "from for meta." }, "to": { "type": "integer", "example": 1, "description": "to for meta." } }, "description": "Pagination, filter, or response metadata for this request." } }, "required": [ "success", "data", "meta" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### GET /api/v1/upgrade Operation: `getUpgradeOptions` View Upgrade Options Return plan and upgrade options available to the organization. Use this before creating a subscription checkout or presenting paid plan choices. Security: ```json [ { "BearerAuth": [] } ] ``` #### Responses - **200**: View Upgrade Options succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "data": { "type": "object", "additionalProperties": true, "properties": { "can_upgrade": { "type": "boolean", "example": true, "description": "Whether the organization can move to the related package or plan." }, "currency": { "type": "string", "example": "GBP", "description": "ISO currency code for the amount shown on the same object." }, "currency_symbol": { "type": "string", "example": "GBP", "description": "Currency symbol displayed with monetary amounts, such as £ or €." }, "current_subscription": { "type": "object", "additionalProperties": true, "properties": { "subscription_id": { "type": "string", "example": "ad3095e4-4628-43d0-8e47-d8996c7daf0d", "format": "uuid", "description": "Stable public subscription reference. Use this value in related endpoint paths and request bodies." }, "status": { "type": "string", "example": "active", "description": "Current lifecycle status for this record." }, "is_active": { "type": "boolean", "example": true, "description": "is active for current_subscription." }, "package": { "type": "object", "additionalProperties": true, "properties": { "package_id": { "type": "string", "example": "f3e184c8-8b3a-45b8-9bcb-cc12f70826b6", "format": "uuid", "description": "Stable public package reference. Use this value in related endpoint paths and request bodies." }, "name": { "type": "string", "example": "Growth Distribution Monthly", "description": "Display name for this package." }, "type": { "type": "string", "example": "membership", "description": "Public type or role value for this item." }, "status": { "type": "string", "example": "published", "description": "Current lifecycle status for this record." }, "price": { "type": "integer", "example": 49, "description": "price for package." }, "currency": { "type": "string", "example": "GBP", "description": "ISO currency code for the amount shown on the same object." }, "royalty_percentage": { "type": "integer", "example": 85, "description": "royalty percentage for package." }, "artist_profile_limit": { "type": "integer", "example": 25, "description": "artist profile limit for package." }, "release_limit": { "type": "integer", "example": 50, "description": "release limit for package." }, "release_limit_cycle": { "type": "string", "example": "monthly", "description": "release limit cycle for package." }, "feature_list": { "type": "array", "items": { "type": "string", "example": "Unlimited team members" }, "description": "feature list for package." } }, "description": "package for current_subscription." }, "subscribed_at": { "type": "string", "example": "2026-06-01T09:00:00+00:00", "format": "date-time", "description": "Timestamp for when subscribed occurred, formatted as ISO 8601 when available." }, "next_payment": { "type": "string", "example": "2026-08-01T09:00:00+00:00", "format": "date-time", "description": "next payment for current_subscription." }, "amount": { "type": "integer", "example": 49, "description": "Monetary amount in the currency shown on the same object." }, "total_paid_amount": { "type": "integer", "example": 98, "description": "Monetary amount in the currency shown on the same object." }, "gateway": { "type": "string", "example": "stripe", "description": "Payment gateway used for this checkout or billing flow.", "enum": [ "airwallex", "stripe", "paypal" ] } }, "description": "Subscription currently active for the organization." }, "packages": { "type": "array", "items": { "type": "object", "additionalProperties": true, "properties": { "package_id": { "type": "string", "example": "f3e184c8-8b3a-45b8-9bcb-cc12f70826b6", "format": "uuid", "description": "Stable public package reference. Use this value in related endpoint paths and request bodies." }, "name": { "type": "string", "example": "Growth Distribution Monthly", "description": "Display name for this packages." }, "type": { "type": "string", "example": "membership", "description": "Public type or role value for this item." }, "status": { "type": "string", "example": "published", "description": "Current lifecycle status for this record." }, "price": { "type": "integer", "example": 49, "description": "price for packages." }, "currency": { "type": "string", "example": "GBP", "description": "ISO currency code for the amount shown on the same object." }, "royalty_percentage": { "type": "integer", "example": 85, "description": "royalty percentage for packages." }, "artist_profile_limit": { "type": "integer", "example": 25, "description": "artist profile limit for packages." }, "release_limit": { "type": "integer", "example": 50, "description": "release limit for packages." }, "release_limit_cycle": { "type": "string", "example": "monthly", "description": "release limit cycle for packages." }, "feature_list": { "type": "array", "items": { "type": "string", "example": "Unlimited team members" }, "description": "feature list for packages." } } }, "description": "Membership packages available to the organization." }, "pay_per_release_plans": { "type": "array", "items": { "type": "object", "additionalProperties": true, "properties": { "plan_id": { "type": "string", "example": "d93dfb89-27ef-4104-a609-4e6dbd272c37", "format": "uuid", "description": "Stable public plan reference. Use this value in related endpoint paths and request bodies." }, "name": { "type": "string", "example": "Single Release Credit", "description": "Display name for this pay_per_release_plans." }, "release_type": { "type": "string", "example": "single", "description": "release type for pay_per_release_plans." }, "active": { "type": "boolean", "example": true, "description": "active for pay_per_release_plans." }, "price": { "type": "integer", "example": 9, "description": "price for pay_per_release_plans." }, "currency": { "type": "string", "example": "GBP", "description": "ISO currency code for the amount shown on the same object." }, "royalty_percentage": { "type": "integer", "example": 90, "description": "royalty percentage for pay_per_release_plans." }, "feature_list": { "type": "array", "items": { "type": "string", "example": "One single release" }, "description": "feature list for pay_per_release_plans." } } }, "description": "Pay-per-release plans available to the organization." }, "available_gateways": { "type": "object", "additionalProperties": true, "properties": { "stripe": { "type": "boolean", "example": true, "description": "Whether stripe checkout is available for this organization." }, "paypal": { "type": "boolean", "example": true, "description": "Whether paypal checkout is available for this organization." }, "airwallex": { "type": "boolean", "example": true, "description": "Whether airwallex checkout is available for this organization." } }, "description": "Saved payment methods visible to the organization for billing and checkout recovery." } }, "description": "Primary response payload for this request." } }, "required": [ "success", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ## Billing and Checkouts Create and verify release, subscription, credit, and payment-method workflows without exposing provider credentials. ### GET /api/v1/billing/invoices/{checkout_id}/pdf Operation: `downloadBillingInvoicePdf` Download Billing Invoice PDF Download the invoice PDF associated with a checkout_id from billing history. Use the checkout_id returned by checkout or billing history responses, not a numeric transaction reference. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `checkout_id` in path (string, required): Checkout reference from billing history. #### Responses - **200**: Returns the invoice PDF file for the requested public checkout reference. **application/pdf** ```json { "type": "string", "format": "binary" } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **404**: Resource not found. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### GET /api/v1/billing/overview Operation: `getBillingOverview` View Billing Overview Return organization billing status, saved payment methods, subscription state, history items, and invoice links that the caller is allowed to manage. Security: ```json [ { "BearerAuth": [] } ] ``` #### Responses - **200**: View Billing Overview succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "data": { "type": "object", "additionalProperties": true, "properties": { "summary": { "type": "object", "additionalProperties": true, "properties": { "active_membership_count": { "type": "integer", "example": 1, "description": "Number of active membership records visible in this context." }, "active_addon_count": { "type": "integer", "example": 2, "description": "Number of active addon records visible in this context." }, "active_subscription_count": { "type": "integer", "example": 3, "description": "Number of active subscription records visible in this context." }, "mrr": { "type": "integer", "example": 87, "description": "mrr for summary." }, "currency": { "type": "string", "example": "GBP", "description": "ISO currency code for the amount shown on the same object." } }, "example": { "active_membership_count": 1, "active_addon_count": 2, "active_subscription_count": 3, "mrr": 87, "currency": "GBP" }, "description": "Short summary value for this object or workflow." }, "payment_methods": { "type": "array", "items": { "type": "object", "additionalProperties": true, "properties": { "payment_method_id": { "type": "string", "example": "payment_method_docs_invalid", "description": "Opaque saved payment method reference returned by billing overview. Do not parse provider details from this value." }, "gateway": { "type": "string", "example": "airwallex", "description": "Payment gateway used for this checkout or billing flow.", "enum": [ "airwallex", "stripe", "paypal" ] }, "brand": { "type": "string", "example": "visa", "description": "Card brand or payment method brand shown for recognition." }, "last4": { "type": "string", "example": "4242", "description": "Last four digits of a saved card, when available." }, "default": { "type": "boolean", "example": true, "description": "Whether this value is the default choice for the organization." }, "exp_month": { "type": "integer", "example": 9, "description": "Expiration month for a saved card." }, "exp_year": { "type": "integer", "example": 2028, "description": "Expiration year for a saved card." } }, "example": { "payment_method_id": "payment_method_docs_invalid", "gateway": "airwallex", "brand": "visa", "last4": "4242", "default": true, "exp_month": 9, "exp_year": 2028 } }, "example": [ { "payment_method_id": "payment_method_docs_invalid", "gateway": "airwallex", "brand": "visa", "last4": "4242", "default": true, "exp_month": 9, "exp_year": 2028 } ], "description": "Saved payment methods visible to the organization for billing and checkout recovery." }, "payment_recovery": { "type": "object", "additionalProperties": true, "properties": { "gateway": { "type": "string", "example": "airwallex", "description": "Payment gateway used for this checkout or billing flow.", "enum": [ "airwallex", "stripe", "paypal" ] }, "recurring_retry_strategy": { "type": "string", "example": "Automated payment recovery for failed recurring payments.", "description": "recurring retry strategy for payment_recovery." }, "daily": { "type": "string", "example": "One retry around 2 hours after failure.", "description": "daily for payment_recovery." }, "short_cycle": { "type": "string", "example": "Retry daily for 2 to 6 day billing cycles.", "description": "short cycle for payment_recovery." }, "long_cycle": { "type": "string", "example": "Retry every 2 days for up to 14 days on weekly, monthly, and yearly cycles.", "description": "long cycle for payment_recovery." } }, "example": { "gateway": "airwallex", "recurring_retry_strategy": "Automated payment recovery for failed recurring payments.", "daily": "One retry around 2 hours after failure.", "short_cycle": "Retry daily for 2 to 6 day billing cycles.", "long_cycle": "Retry every 2 days for up to 14 days on weekly, monthly, and yearly cycles." }, "description": "Payment recovery state and actions available for failed or incomplete billing attempts." }, "subscriptions": { "type": "array", "items": { "type": "object", "additionalProperties": true, "properties": { "subscription_id": { "type": "string", "example": "ad3095e4-4628-43d0-8e47-d8996c7daf0d", "format": "uuid", "description": "Stable public subscription reference. Use this value in related endpoint paths and request bodies." }, "addon_slug": { "type": "string", "example": "release-smartlinks", "description": "addon slug for subscriptions." }, "addon_name": { "type": "string", "example": "Release Smartlinks", "description": "addon name for subscriptions." }, "status": { "type": "string", "example": "active", "description": "Current lifecycle status for this record." }, "amount": { "type": "integer", "example": 19, "description": "Monetary amount in the currency shown on the same object." }, "currency": { "type": "string", "example": "GBP", "description": "ISO currency code for the amount shown on the same object." }, "cycle": { "type": "string", "example": "monthly", "description": "Billing cycle requested for the add-on checkout, such as monthly or yearly when both are offered." }, "next_billing_at": { "type": "string", "example": "2026-08-01T09:00:00+00:00", "description": "Timestamp for when next billing occurred, formatted as ISO 8601 when available." } }, "example": { "subscription_id": "ad3095e4-4628-43d0-8e47-d8996c7daf0d", "addon_slug": "release-smartlinks", "addon_name": "Release Smartlinks", "status": "active", "amount": 19, "currency": "GBP", "cycle": "monthly", "next_billing_at": "2026-08-01T09:00:00+00:00" } }, "example": [ { "subscription_id": "ad3095e4-4628-43d0-8e47-d8996c7daf0d", "addon_slug": "release-smartlinks", "addon_name": "Release Smartlinks", "status": "active", "amount": 19, "currency": "GBP", "cycle": "monthly", "next_billing_at": "2026-08-01T09:00:00+00:00" } ], "description": "Subscriptions visible to the organization or account." }, "history": { "type": "array", "items": { "type": "object", "additionalProperties": true, "properties": { "checkout_id": { "type": "string", "example": "39b189c1-8f8e-4df2-8632-176f87f791a1", "format": "uuid", "description": "Stable public checkout reference. Use this value in related endpoint paths and request bodies." }, "created_at": { "type": "string", "example": "2026-07-04T10:15:00+00:00", "description": "Timestamp for when created occurred, formatted as ISO 8601 when available." }, "type": { "type": "string", "example": "addon_subscription", "description": "Public type or role value for this item." }, "label": { "type": "string", "example": "Release Smartlinks Monthly", "description": "Label name attached to the release metadata." }, "customer": { "type": "string", "example": "Maya Chen", "description": "customer for history." }, "gateway": { "type": "string", "example": "airwallex", "description": "Payment gateway used for this checkout or billing flow.", "enum": [ "airwallex", "stripe", "paypal" ] }, "status": { "type": "string", "example": "success", "description": "Current lifecycle status for this record." }, "amount": { "type": "integer", "example": 19, "description": "Monetary amount in the currency shown on the same object." }, "currency": { "type": "string", "example": "GBP", "description": "ISO currency code for the amount shown on the same object." }, "invoice_pdf_url": { "type": "string", "example": "/api/v1/billing/invoices/39b189c1-8f8e-4df2-8632-176f87f791a1/pdf", "description": "Organization-scoped URL for downloading the invoice PDF for this checkout." } }, "example": { "checkout_id": "39b189c1-8f8e-4df2-8632-176f87f791a1", "created_at": "2026-07-04T10:15:00+00:00", "type": "addon_subscription", "label": "Release Smartlinks Monthly", "customer": "Maya Chen", "gateway": "airwallex", "status": "success", "amount": 19, "currency": "GBP", "invoice_pdf_url": "/api/v1/billing/invoices/39b189c1-8f8e-4df2-8632-176f87f791a1/pdf" } }, "example": [ { "checkout_id": "39b189c1-8f8e-4df2-8632-176f87f791a1", "created_at": "2026-07-04T10:15:00+00:00", "type": "addon_subscription", "label": "Release Smartlinks Monthly", "customer": "Maya Chen", "gateway": "airwallex", "status": "success", "amount": 19, "currency": "GBP", "invoice_pdf_url": "/api/v1/billing/invoices/39b189c1-8f8e-4df2-8632-176f87f791a1/pdf" } ], "description": "Billing, checkout, wallet, or activity history entries returned for the workflow." } }, "example": { "summary": { "active_membership_count": 1, "active_addon_count": 2, "active_subscription_count": 3, "mrr": 87, "currency": "GBP" }, "payment_methods": [ { "payment_method_id": "payment_method_docs_invalid", "gateway": "airwallex", "brand": "visa", "last4": "4242", "default": true, "exp_month": 9, "exp_year": 2028 } ], "payment_recovery": { "gateway": "airwallex", "recurring_retry_strategy": "Automated payment recovery for failed recurring payments.", "daily": "One retry around 2 hours after failure.", "short_cycle": "Retry daily for 2 to 6 day billing cycles.", "long_cycle": "Retry every 2 days for up to 14 days on weekly, monthly, and yearly cycles." }, "subscriptions": [ { "subscription_id": "ad3095e4-4628-43d0-8e47-d8996c7daf0d", "addon_slug": "release-smartlinks", "addon_name": "Release Smartlinks", "status": "active", "amount": 19, "currency": "GBP", "cycle": "monthly", "next_billing_at": "2026-08-01T09:00:00+00:00" } ], "history": [ { "checkout_id": "39b189c1-8f8e-4df2-8632-176f87f791a1", "created_at": "2026-07-04T10:15:00+00:00", "type": "addon_subscription", "label": "Release Smartlinks Monthly", "customer": "Maya Chen", "gateway": "airwallex", "status": "success", "amount": 19, "currency": "GBP", "invoice_pdf_url": "/api/v1/billing/invoices/39b189c1-8f8e-4df2-8632-176f87f791a1/pdf" } ] }, "description": "Primary response payload for this request." } }, "example": { "success": true, "data": { "summary": { "active_membership_count": 1, "active_addon_count": 2, "active_subscription_count": 3, "mrr": 87, "currency": "GBP" }, "payment_methods": [ { "payment_method_id": "payment_method_docs_invalid", "gateway": "airwallex", "brand": "visa", "last4": "4242", "default": true, "exp_month": 9, "exp_year": 2028 } ], "payment_recovery": { "gateway": "airwallex", "recurring_retry_strategy": "Automated payment recovery for failed recurring payments.", "daily": "One retry around 2 hours after failure.", "short_cycle": "Retry daily for 2 to 6 day billing cycles.", "long_cycle": "Retry every 2 days for up to 14 days on weekly, monthly, and yearly cycles." }, "subscriptions": [ { "subscription_id": "ad3095e4-4628-43d0-8e47-d8996c7daf0d", "addon_slug": "release-smartlinks", "addon_name": "Release Smartlinks", "status": "active", "amount": 19, "currency": "GBP", "cycle": "monthly", "next_billing_at": "2026-08-01T09:00:00+00:00" } ], "history": [ { "checkout_id": "39b189c1-8f8e-4df2-8632-176f87f791a1", "created_at": "2026-07-04T10:15:00+00:00", "type": "addon_subscription", "label": "Release Smartlinks Monthly", "customer": "Maya Chen", "gateway": "airwallex", "status": "success", "amount": 19, "currency": "GBP", "invoice_pdf_url": "/api/v1/billing/invoices/39b189c1-8f8e-4df2-8632-176f87f791a1/pdf" } ] } }, "required": [ "success", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### POST /api/v1/billing/activation-trial/cancel Operation: `cancelActivationTrial` Cancel Activation Trial Cancel the current organization activation trial before its activation charge is attempted. The response returns the updated activation trial state. Security: ```json [ { "BearerAuth": [] } ] ``` #### Responses - **200**: The activation trial was canceled. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true }, "message": { "type": "string", "example": "Trial canceled. No activation fee will be charged automatically." }, "data": { "type": "object", "additionalProperties": true, "properties": { "activation_trial": { "type": [ "object", "null" ], "additionalProperties": true, "description": "Updated activation trial lifecycle state." } } } } } ``` - **401**: Authentication is required. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: The caller cannot manage organization billing. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **422**: The trial cannot be canceled in its current state. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### DELETE /api/v1/billing/payment-methods/{payment_method_id} Operation: `deletePaymentMethod` Delete Payment Method Remove a saved payment method by payment_method_id when billing rules allow it. The response confirms removal or explains why the method must remain available. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `payment_method_id` in path (string, required): Opaque saved payment method reference returned by the billing overview. Do not parse provider details from this value. #### Responses - **200**: Delete Payment Method succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "Payment method deleted.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." } }, "required": [ "success", "message" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **404**: Resource not found. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### POST /api/v1/billing/payment-methods/{payment_method_id}/default Operation: `setDefaultPaymentMethod` Set Default Payment Method Set a saved payment method as the organization default by payment_method_id. Use this after listing billing overview or adding a new payment method. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `payment_method_id` in path (string, required): Opaque saved payment method reference returned by the billing overview. Do not parse provider details from this value. #### Responses - **200**: Set Default Payment Method succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "Default payment method updated.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." } }, "required": [ "success", "message" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **404**: Resource not found. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### POST /api/v1/billing/payment-methods/{payment_method_id}/manage Operation: `createPaymentMethodManagementSession` Create Payment Method Management Session Create a hosted payment method management session for a saved payment method by payment_method_id when external management is required. The response returns a redirect_url when available. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `payment_method_id` in path (string, required): Opaque saved payment method reference returned by the billing overview. Do not parse provider details from this value. #### Responses - **200**: Create Payment Method Management Session succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "Management flow created.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." }, "data": { "type": "object", "additionalProperties": true, "properties": { "payment_method_id": { "type": "string", "example": "payment_method_docs_invalid", "description": "Opaque saved payment method reference returned by billing overview. Do not parse provider details from this value." }, "manage_url": { "type": "string", "example": "https://checkout.spacemedia-docs.invalid/payment-methods/manage/docs-payment-method", "format": "uri", "description": "Public URL returned for this resource or action." } }, "description": "Primary response payload for this request." } }, "required": [ "success", "message", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **404**: Resource not found. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### POST /api/v1/billing/payment-methods/paypal/setup Operation: `startPaypalPaymentMethodSetup` Start PayPal Payment Method Setup Start a hosted PayPal payment method setup flow for the organization. Redirect the user to redirect_url, then verify with checkout_id after the provider returns. Security: ```json [ { "BearerAuth": [] } ] ``` #### Request body Request payload. Required. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success_url": { "type": "string", "example": "https://northstar-distribution.co.uk/billing/paypal/success", "format": "uri", "description": "Public URL returned for this resource or action." }, "cancel_url": { "type": "string", "example": "https://northstar-distribution.co.uk/billing/paypal/cancel", "format": "uri", "description": "Public URL returned for this resource or action." } }, "required": [ "success_url", "cancel_url" ] } ``` #### Responses - **200**: Start PayPal Payment Method Setup succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "Payment method setup created.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." }, "data": { "type": "object", "additionalProperties": true, "properties": { "checkout_id": { "type": "string", "example": "39b189c1-8f8e-4df2-8632-176f87f791a1", "format": "uuid", "description": "Stable public checkout reference. Use this value in related endpoint paths and request bodies." }, "gateway": { "type": "string", "example": "paypal", "description": "Payment gateway used for this checkout or billing flow.", "enum": [ "airwallex", "stripe", "paypal" ] }, "redirect_url": { "type": "string", "example": "https://checkout.spacemedia-docs.invalid/session/docs-checkout-session", "format": "uri", "description": "Hosted checkout or management URL where the user should continue the flow." } }, "description": "Primary response payload for this request." } }, "required": [ "success", "message", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **422**: Validation failed for success_url. The request was not applied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### POST /api/v1/billing/payment-methods/paypal/setup/verify Operation: `verifyPaypalPaymentMethodSetup` Verify PayPal Payment Method Setup Verify a PayPal payment method setup by checkout_id after the user returns from the provider. The response confirms whether the billing agreement was saved. Security: ```json [ { "BearerAuth": [] } ] ``` #### Request body Request payload. Required. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "checkout_id": { "type": "string", "example": "39b189c1-8f8e-4df2-8632-176f87f791a1", "format": "uuid", "description": "Stable public checkout reference. Use this value in related endpoint paths and request bodies." } }, "required": [ "checkout_id" ] } ``` #### Responses - **200**: Verify PayPal Payment Method Setup succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "Payment method verified.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." }, "data": { "type": "object", "additionalProperties": true, "properties": { "payment_method_id": { "type": "string", "example": "payment_method_docs_invalid", "description": "Opaque saved payment method reference returned by billing overview. Do not parse provider details from this value." }, "gateway": { "type": "string", "example": "paypal", "description": "Payment gateway used for this checkout or billing flow.", "enum": [ "airwallex", "stripe", "paypal" ] }, "default": { "type": "boolean", "example": false, "description": "Whether this value is the default choice for the organization." } }, "description": "Primary response payload for this request." } }, "required": [ "success", "message", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **422**: Validation failed for checkout_id. The request was not applied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### POST /api/v1/billing/payment-methods/stripe/setup Operation: `startStripePaymentMethodSetup` Start Stripe Payment Method Setup Start a hosted Stripe payment method setup flow for the organization. Redirect the user to redirect_url, then verify with checkout_id after the provider returns. Security: ```json [ { "BearerAuth": [] } ] ``` #### Request body Request payload. Required. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success_url": { "type": "string", "example": "https://northstar-distribution.co.uk/billing/payment-methods/success", "format": "uri", "description": "Public URL returned for this resource or action." }, "cancel_url": { "type": "string", "example": "https://northstar-distribution.co.uk/billing/payment-methods/cancel", "format": "uri", "description": "Public URL returned for this resource or action." } }, "required": [ "success_url", "cancel_url" ] } ``` #### Responses - **200**: Start Stripe Payment Method Setup succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "Payment method setup created.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." }, "data": { "type": "object", "additionalProperties": true, "properties": { "checkout_id": { "type": "string", "example": "39b189c1-8f8e-4df2-8632-176f87f791a1", "format": "uuid", "description": "Stable public checkout reference. Use this value in related endpoint paths and request bodies." }, "gateway": { "type": "string", "example": "stripe", "description": "Payment gateway used for this checkout or billing flow.", "enum": [ "airwallex", "stripe", "paypal" ] }, "redirect_url": { "type": "string", "example": "https://checkout.spacemedia-docs.invalid/session/docs-checkout-session", "format": "uri", "description": "Hosted checkout or management URL where the user should continue the flow." } }, "description": "Primary response payload for this request." } }, "required": [ "success", "message", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **422**: Validation failed for success_url. The request was not applied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### POST /api/v1/billing/payment-methods/stripe/setup/intent Operation: `createEmbeddedPaymentMethodSetup` Create Embedded Payment Method Setup Create an embedded payment method setup session for collecting a payment method inside your interface. Store checkout_id and use embedded_checkout_token only in the payment collection component. Security: ```json [ { "BearerAuth": [] } ] ``` #### Responses - **200**: Create Embedded Payment Method Setup succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "Setup intent created.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." }, "data": { "type": "object", "additionalProperties": true, "properties": { "checkout_id": { "type": "string", "example": "39b189c1-8f8e-4df2-8632-176f87f791a1", "format": "uuid", "description": "Stable public checkout reference. Use this value in related endpoint paths and request bodies." }, "gateway": { "type": "string", "example": "stripe", "description": "Payment gateway used for this checkout or billing flow.", "enum": [ "airwallex", "stripe", "paypal" ] }, "embedded_checkout_token": { "type": "string", "example": "docs_invalid_embedded_checkout_token", "description": "Short-lived embedded checkout token. Treat this value as sensitive payment data and never log it or expose it in support tickets.", "format": "password", "x-sensitive": true } }, "description": "Primary response payload for this request." } }, "required": [ "success", "message", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### POST /api/v1/billing/payment-methods/stripe/setup/intent/verify Operation: `verifyStripeSetupIntent` Verify Embedded Stripe Setup Intent Verify an embedded Stripe payment method setup by checkout_id after the payment component confirms completion. The response returns the saved payment method state. Security: ```json [ { "BearerAuth": [] } ] ``` #### Request body Request payload. Required. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "checkout_id": { "type": "string", "example": "39b189c1-8f8e-4df2-8632-176f87f791a1", "format": "uuid", "description": "Stable public checkout reference. Use this value in related endpoint paths and request bodies." } }, "required": [ "checkout_id" ] } ``` #### Responses - **200**: Verify Embedded Stripe Setup Intent succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "Payment method verified.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." }, "data": { "type": "object", "additionalProperties": true, "properties": { "payment_method_id": { "type": "string", "example": "payment_method_docs_invalid", "description": "Opaque saved payment method reference returned by billing overview. Do not parse provider details from this value." }, "gateway": { "type": "string", "example": "stripe", "description": "Payment gateway used for this checkout or billing flow.", "enum": [ "airwallex", "stripe", "paypal" ] }, "default": { "type": "boolean", "example": true, "description": "Whether this value is the default choice for the organization." } }, "description": "Primary response payload for this request." } }, "required": [ "success", "message", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **422**: Validation failed for checkout_id. The request was not applied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### POST /api/v1/billing/payment-methods/stripe/setup/verify Operation: `verifyStripePaymentMethodSetup` Verify Stripe Payment Method Setup Verify a hosted Stripe payment method setup by checkout_id after the user returns from the provider. The response confirms whether the payment method was saved. Security: ```json [ { "BearerAuth": [] } ] ``` #### Request body Request payload. Required. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "checkout_id": { "type": "string", "example": "39b189c1-8f8e-4df2-8632-176f87f791a1", "format": "uuid", "description": "Stable public checkout reference. Use this value in related endpoint paths and request bodies." } }, "required": [ "checkout_id" ] } ``` #### Responses - **200**: Verify Stripe Payment Method Setup succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "Payment method verified.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." }, "data": { "type": "object", "additionalProperties": true, "properties": { "payment_method_id": { "type": "string", "example": "payment_method_docs_invalid", "description": "Opaque saved payment method reference returned by billing overview. Do not parse provider details from this value." }, "gateway": { "type": "string", "example": "stripe", "description": "Payment gateway used for this checkout or billing flow.", "enum": [ "airwallex", "stripe", "paypal" ] }, "default": { "type": "boolean", "example": true, "description": "Whether this value is the default choice for the organization." } }, "description": "Primary response payload for this request." } }, "required": [ "success", "message", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **422**: Validation failed for checkout_id. The request was not applied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### POST /api/v1/billing/subscriptions/{subscription_type}/{subscription_id}/cancel Operation: `cancelBillingSubscription` Cancel Billing Subscription Cancel an organization billing subscription by subscription_type and subscription_id. The response confirms the cancellation state visible to the caller. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `subscription_type` in path (string, required): Subscription family to update. - `subscription_id` in path (string, required): Public subscription reference returned by the API. #### Responses - **200**: Cancel Billing Subscription succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "Subscription cancelled.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." } }, "required": [ "success", "message" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **404**: Resource not found. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### POST /api/v1/billing/subscriptions/{subscription_type}/{subscription_id}/resume Operation: `resumeBillingSubscription` Resume Billing Subscription Resume a canceled or paused organization billing subscription by subscription_type and subscription_id when the plan state allows it. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `subscription_type` in path (string, required): Subscription family to update. - `subscription_id` in path (string, required): Public subscription reference returned by the API. #### Responses - **200**: Resume Billing Subscription succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "Subscription resumed.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." } }, "required": [ "success", "message" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **404**: Resource not found. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### POST /api/v1/order/{release_id}/checkout/airwallex Operation: `createAirwallexReleaseCheckout` Create Airwallex Release Checkout Create Airwallex Release Checkout. Use it to start checkouts, verify completion, manage saved payment methods, inspect invoices, and cancel or resume organization billing subscriptions. It applies the requested change and returns the updated resource, validation result, or action status needed for the next API step. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `release_id` in path (string, required): Public release reference returned by the API. #### Request body Request payload. Required. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success_url": { "type": "string", "example": "https://northstar-distribution.co.uk/releases/midnight-atlas/payment/success", "format": "uri", "description": "Public URL returned for this resource or action." }, "cancel_url": { "type": "string", "example": "https://northstar-distribution.co.uk/releases/midnight-atlas/payment/cancel", "format": "uri", "description": "Public URL returned for this resource or action." } }, "required": [ "success_url", "cancel_url" ] } ``` #### Responses - **200**: Create Airwallex Release Checkout succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "Checkout created.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." }, "data": { "type": "object", "additionalProperties": true, "properties": { "checkout_id": { "type": "string", "example": "39b189c1-8f8e-4df2-8632-176f87f791a1", "format": "uuid", "description": "Stable public checkout reference. Use this value in related endpoint paths and request bodies." }, "gateway": { "type": "string", "example": "airwallex", "description": "Payment gateway used for this checkout or billing flow.", "enum": [ "airwallex", "stripe", "paypal" ] }, "status": { "type": "string", "example": "pending", "description": "Current lifecycle status for this record." }, "redirect_url": { "type": "string", "example": "https://checkout.spacemedia-docs.invalid/session/docs-checkout-session", "format": "uri", "description": "Hosted checkout or management URL where the user should continue the flow." }, "embedded_checkout_token": { "type": "string", "example": "docs_invalid_embedded_checkout_token", "description": "Short-lived embedded checkout token. Treat this value as sensitive payment data and never log it or expose it in support tickets.", "format": "password", "x-sensitive": true }, "amount": { "type": "integer", "example": 49, "description": "Monetary amount in the currency shown on the same object." }, "currency": { "type": "string", "example": "GBP", "description": "ISO currency code for the amount shown on the same object." }, "expires_at": { "type": "string", "example": "2026-07-04T10:30:00+00:00", "format": "date-time", "description": "Timestamp for when expires occurred, formatted as ISO 8601 when available." }, "release": { "type": "object", "additionalProperties": true, "properties": { "release_id": { "type": "string", "example": "b7a15d95-58f6-4f67-b5d1-89f4f5bfb4d8", "format": "uuid", "description": "Stable public release reference. Use this value in related endpoint paths and request bodies." }, "title": { "type": "string", "example": "Midnight Atlas", "description": "Catalog or content title shown in the dashboard and API responses." }, "status": { "type": "string", "example": "draft", "description": "Current lifecycle status for this record." } }, "description": "Release summary or nested release object connected to this workflow." } }, "description": "Primary response payload for this request." } }, "required": [ "success", "message", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **404**: Resource not found. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **422**: Validation failed for success_url. The request was not applied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### POST /api/v1/order/{release_id}/checkout/paypal Operation: `createPaypalReleaseCheckout` Create PayPal Release Checkout Create PayPal Release Checkout. Use it to start checkouts, verify completion, manage saved payment methods, inspect invoices, and cancel or resume organization billing subscriptions. It applies the requested change and returns the updated resource, validation result, or action status needed for the next API step. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `release_id` in path (string, required): Public release reference returned by the API. #### Request body Request payload. Required. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success_url": { "type": "string", "example": "https://northstar-distribution.co.uk/releases/midnight-atlas/payment/success", "format": "uri", "description": "Public URL returned for this resource or action." }, "cancel_url": { "type": "string", "example": "https://northstar-distribution.co.uk/releases/midnight-atlas/payment/cancel", "format": "uri", "description": "Public URL returned for this resource or action." } }, "required": [ "success_url", "cancel_url" ] } ``` #### Responses - **200**: Create PayPal Release Checkout succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "Checkout created.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." }, "data": { "type": "object", "additionalProperties": true, "properties": { "checkout_id": { "type": "string", "example": "39b189c1-8f8e-4df2-8632-176f87f791a1", "format": "uuid", "description": "Stable public checkout reference. Use this value in related endpoint paths and request bodies." }, "gateway": { "type": "string", "example": "paypal", "description": "Payment gateway used for this checkout or billing flow.", "enum": [ "airwallex", "stripe", "paypal" ] }, "status": { "type": "string", "example": "pending", "description": "Current lifecycle status for this record." }, "redirect_url": { "type": "string", "example": "https://checkout.spacemedia-docs.invalid/session/docs-checkout-session", "format": "uri", "description": "Hosted checkout or management URL where the user should continue the flow." }, "amount": { "type": "integer", "example": 49, "description": "Monetary amount in the currency shown on the same object." }, "currency": { "type": "string", "example": "GBP", "description": "ISO currency code for the amount shown on the same object." }, "expires_at": { "type": "string", "example": "2026-07-04T10:30:00+00:00", "description": "Timestamp for when expires occurred, formatted as ISO 8601 when available." }, "release": { "type": "object", "additionalProperties": true, "properties": { "release_id": { "type": "string", "example": "b7a15d95-58f6-4f67-b5d1-89f4f5bfb4d8", "format": "uuid", "description": "Stable public release reference. Use this value in related endpoint paths and request bodies." }, "title": { "type": "string", "example": "Midnight Atlas", "description": "Catalog or content title shown in the dashboard and API responses." }, "status": { "type": "string", "example": "draft", "description": "Current lifecycle status for this record." } }, "example": { "release_id": "b7a15d95-58f6-4f67-b5d1-89f4f5bfb4d8", "title": "Midnight Atlas", "status": "draft" }, "description": "Release summary or nested release object connected to this workflow." } }, "example": { "checkout_id": "39b189c1-8f8e-4df2-8632-176f87f791a1", "gateway": "paypal", "status": "pending", "redirect_url": "https://checkout.spacemedia-docs.invalid/session/docs-checkout-session", "amount": 49, "currency": "GBP", "expires_at": "2026-07-04T10:30:00+00:00", "release": { "release_id": "b7a15d95-58f6-4f67-b5d1-89f4f5bfb4d8", "title": "Midnight Atlas", "status": "draft" } }, "description": "Primary response payload for this request." } }, "example": { "success": true, "message": "Checkout created.", "data": { "checkout_id": "39b189c1-8f8e-4df2-8632-176f87f791a1", "gateway": "paypal", "status": "pending", "redirect_url": "https://checkout.spacemedia-docs.invalid/session/docs-checkout-session", "amount": 49, "currency": "GBP", "expires_at": "2026-07-04T10:30:00+00:00", "release": { "release_id": "b7a15d95-58f6-4f67-b5d1-89f4f5bfb4d8", "title": "Midnight Atlas", "status": "draft" } } }, "required": [ "success", "message", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **404**: Resource not found. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **422**: Validation failed for success_url. The request was not applied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### POST /api/v1/order/{release_id}/checkout/stripe Operation: `createStripeReleaseCheckout` Create Stripe Release Checkout Create Stripe Release Checkout. Use it to start checkouts, verify completion, manage saved payment methods, inspect invoices, and cancel or resume organization billing subscriptions. It applies the requested change and returns the updated resource, validation result, or action status needed for the next API step. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `release_id` in path (string, required): Public release reference returned by the API. #### Request body Request payload. Required. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success_url": { "type": "string", "example": "https://northstar-distribution.co.uk/releases/midnight-atlas/payment/success", "format": "uri", "description": "Public URL returned for this resource or action." }, "cancel_url": { "type": "string", "example": "https://northstar-distribution.co.uk/releases/midnight-atlas/payment/cancel", "format": "uri", "description": "Public URL returned for this resource or action." } }, "required": [ "success_url", "cancel_url" ] } ``` #### Responses - **200**: Create Stripe Release Checkout succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "Checkout created.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." }, "data": { "type": "object", "additionalProperties": true, "properties": { "checkout_id": { "type": "string", "example": "39b189c1-8f8e-4df2-8632-176f87f791a1", "format": "uuid", "description": "Stable public checkout reference. Use this value in related endpoint paths and request bodies." }, "gateway": { "type": "string", "example": "stripe", "description": "Payment gateway used for this checkout or billing flow.", "enum": [ "airwallex", "stripe", "paypal" ] }, "status": { "type": "string", "example": "pending", "description": "Current lifecycle status for this record." }, "redirect_url": { "type": "string", "example": "https://checkout.spacemedia-docs.invalid/session/docs-checkout-session", "format": "uri", "description": "Hosted checkout or management URL where the user should continue the flow." }, "amount": { "type": "integer", "example": 49, "description": "Monetary amount in the currency shown on the same object." }, "currency": { "type": "string", "example": "GBP", "description": "ISO currency code for the amount shown on the same object." }, "expires_at": { "type": "string", "example": "2026-07-04T10:30:00+00:00", "description": "Timestamp for when expires occurred, formatted as ISO 8601 when available." }, "release": { "type": "object", "additionalProperties": true, "properties": { "release_id": { "type": "string", "example": "b7a15d95-58f6-4f67-b5d1-89f4f5bfb4d8", "format": "uuid", "description": "Stable public release reference. Use this value in related endpoint paths and request bodies." }, "title": { "type": "string", "example": "Midnight Atlas", "description": "Catalog or content title shown in the dashboard and API responses." }, "status": { "type": "string", "example": "draft", "description": "Current lifecycle status for this record." } }, "example": { "release_id": "b7a15d95-58f6-4f67-b5d1-89f4f5bfb4d8", "title": "Midnight Atlas", "status": "draft" }, "description": "Release summary or nested release object connected to this workflow." } }, "example": { "checkout_id": "39b189c1-8f8e-4df2-8632-176f87f791a1", "gateway": "stripe", "status": "pending", "redirect_url": "https://checkout.spacemedia-docs.invalid/session/docs-checkout-session", "amount": 49, "currency": "GBP", "expires_at": "2026-07-04T10:30:00+00:00", "release": { "release_id": "b7a15d95-58f6-4f67-b5d1-89f4f5bfb4d8", "title": "Midnight Atlas", "status": "draft" } }, "description": "Primary response payload for this request." } }, "example": { "success": true, "message": "Checkout created.", "data": { "checkout_id": "39b189c1-8f8e-4df2-8632-176f87f791a1", "gateway": "stripe", "status": "pending", "redirect_url": "https://checkout.spacemedia-docs.invalid/session/docs-checkout-session", "amount": 49, "currency": "GBP", "expires_at": "2026-07-04T10:30:00+00:00", "release": { "release_id": "b7a15d95-58f6-4f67-b5d1-89f4f5bfb4d8", "title": "Midnight Atlas", "status": "draft" } } }, "required": [ "success", "message", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **404**: Resource not found. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **422**: Validation failed for success_url. The request was not applied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### POST /api/v1/order/checkout/verify Operation: `verifyReleaseCheckout` Verify Release Checkout Verify a release checkout by checkout_id after payment completion. The response updates the related release order and returns a payment status suitable for the next catalog step. Security: ```json [ { "BearerAuth": [] } ] ``` #### Request body Request payload. Required. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "checkout_id": { "type": "string", "example": "39b189c1-8f8e-4df2-8632-176f87f791a1", "format": "uuid", "description": "Stable public checkout reference. Use this value in related endpoint paths and request bodies." } }, "required": [ "checkout_id" ] } ``` #### Responses - **200**: Verify Release Checkout succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "Release checkout verified.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." }, "data": { "type": "object", "additionalProperties": true, "properties": { "checkout_id": { "type": "string", "example": "39b189c1-8f8e-4df2-8632-176f87f791a1", "format": "uuid", "description": "Stable public checkout reference. Use this value in related endpoint paths and request bodies." }, "release": { "type": "object", "additionalProperties": true, "properties": { "release_id": { "type": "string", "example": "b7a15d95-58f6-4f67-b5d1-89f4f5bfb4d8", "format": "uuid", "description": "Stable public release reference. Use this value in related endpoint paths and request bodies." }, "title": { "type": "string", "example": "Midnight Atlas", "description": "Catalog or content title shown in the dashboard and API responses." }, "status": { "type": "string", "example": "draft", "description": "Current lifecycle status for this record." } }, "description": "Release summary or nested release object connected to this workflow." }, "status": { "type": "string", "example": "paid", "description": "Current lifecycle status for this record." } }, "description": "Primary response payload for this request." } }, "required": [ "success", "message", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **422**: Validation failed for checkout_id. The request was not applied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### POST /api/v1/order/credits/checkout Operation: `createCreditsCheckout` Create Credits Checkout Create a checkout for organization credits. Store checkout_id, send the user through the returned payment flow, and verify the checkout before increasing available balance. Security: ```json [ { "BearerAuth": [] } ] ``` #### Request body Request payload. Required. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "amount": { "type": "integer", "example": 50, "description": "Monetary amount in the currency shown on the same object." }, "payment_method": { "type": "string", "example": "airwallex", "description": "Payment method selected for the checkout, using a supported public gateway or saved method value." }, "success_url": { "type": "string", "example": "https://northstar-distribution.co.uk/billing/credits/success", "format": "uri", "description": "Public URL returned for this resource or action." }, "cancel_url": { "type": "string", "example": "https://northstar-distribution.co.uk/billing/credits/cancel", "format": "uri", "description": "Public URL returned for this resource or action." } }, "required": [ "amount", "payment_method" ] } ``` #### Responses - **200**: Create Credits Checkout succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "Checkout created.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." }, "data": { "type": "object", "additionalProperties": true, "properties": { "checkout_id": { "type": "string", "example": "39b189c1-8f8e-4df2-8632-176f87f791a1", "format": "uuid", "description": "Stable public checkout reference. Use this value in related endpoint paths and request bodies." }, "gateway": { "type": "string", "example": "airwallex", "description": "Payment gateway used for this checkout or billing flow.", "enum": [ "airwallex", "stripe", "paypal" ] }, "status": { "type": "string", "example": "pending", "description": "Current lifecycle status for this record." }, "redirect_url": { "type": "string", "example": "https://checkout.spacemedia-docs.invalid/session/docs-checkout-session", "format": "uri", "description": "Hosted checkout or management URL where the user should continue the flow." }, "embedded_checkout_token": { "type": "string", "example": "docs_invalid_embedded_checkout_token", "description": "Short-lived embedded checkout token. Treat this value as sensitive payment data and never log it or expose it in support tickets.", "format": "password", "x-sensitive": true }, "amount": { "type": "integer", "example": 50, "description": "Monetary amount in the currency shown on the same object." }, "currency": { "type": "string", "example": "GBP", "description": "ISO currency code for the amount shown on the same object." }, "expires_at": { "type": "string", "example": "2026-07-04T10:30:00+00:00", "format": "date-time", "description": "Timestamp for when expires occurred, formatted as ISO 8601 when available." } }, "description": "Primary response payload for this request." } }, "required": [ "success", "message", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **422**: Validation failed for amount. The request was not applied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### POST /api/v1/order/credits/checkout/verify Operation: `verifyCreditsCheckout` Verify Credits Checkout Verify a credits checkout by checkout_id after payment completion. The response confirms whether the credit balance update has been applied. Security: ```json [ { "BearerAuth": [] } ] ``` #### Request body Request payload. Required. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "checkout_id": { "type": "string", "example": "39b189c1-8f8e-4df2-8632-176f87f791a1", "format": "uuid", "description": "Stable public checkout reference. Use this value in related endpoint paths and request bodies." } }, "required": [ "checkout_id" ] } ``` #### Responses - **200**: Verify Credits Checkout succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "Credits checkout verified.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." }, "data": { "type": "object", "additionalProperties": true, "properties": { "checkout_id": { "type": "string", "example": "39b189c1-8f8e-4df2-8632-176f87f791a1", "format": "uuid", "description": "Stable public checkout reference. Use this value in related endpoint paths and request bodies." }, "credits_added": { "type": "integer", "example": 50, "description": "Number of credits added after a successful top-up or credit checkout." }, "balance": { "type": "integer", "example": 170, "description": "Current credit, wallet, or account balance shown in the response currency or unit." } }, "description": "Primary response payload for this request." } }, "required": [ "success", "message", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **422**: Validation failed for checkout_id. The request was not applied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### GET /api/v1/subscriptions Operation: `listSubscriptions` List Subscriptions List Subscriptions. Use it to start checkouts, verify completion, manage saved payment methods, inspect invoices, and cancel or resume organization billing subscriptions. It returns public references and organization-visible fields only, so clients can safely use returned values in follow-up API calls. Security: ```json [ { "BearerAuth": [] } ] ``` #### Responses - **200**: List Subscriptions succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "data": { "type": "array", "items": { "type": "object", "additionalProperties": true, "properties": { "subscription_id": { "type": "string", "example": "ad3095e4-4628-43d0-8e47-d8996c7daf0d", "format": "uuid", "description": "Stable public subscription reference. Use this value in related endpoint paths and request bodies." }, "status": { "type": "string", "example": "active", "description": "Current lifecycle status for this record." }, "is_active": { "type": "boolean", "example": true, "description": "Whether the subscription, plan, add-on, or resource is currently active." }, "package": { "type": "object", "additionalProperties": true, "properties": { "package_id": { "type": "string", "example": "f3e184c8-8b3a-45b8-9bcb-cc12f70826b6", "format": "uuid", "description": "Stable public package reference. Use this value in related endpoint paths and request bodies." }, "name": { "type": "string", "example": "Growth Distribution Monthly", "description": "Display name for this package." }, "type": { "type": "string", "example": "membership", "description": "Public type or role value for this item." }, "status": { "type": "string", "example": "published", "description": "Current lifecycle status for this record." }, "price": { "type": "integer", "example": 49, "description": "price for package." }, "currency": { "type": "string", "example": "GBP", "description": "ISO currency code for the amount shown on the same object." }, "royalty_percentage": { "type": "integer", "example": 85, "description": "royalty percentage for package." }, "artist_profile_limit": { "type": "integer", "example": 25, "description": "artist profile limit for package." }, "release_limit": { "type": "integer", "example": 50, "description": "release limit for package." }, "release_limit_cycle": { "type": "string", "example": "monthly", "description": "release limit cycle for package." }, "feature_list": { "type": "array", "items": { "type": "string", "example": "Unlimited team members" }, "description": "feature list for package." } }, "description": "Membership package attached to the subscription or checkout." }, "subscribed_at": { "type": "string", "example": "2026-06-01T09:00:00+00:00", "format": "date-time", "description": "Timestamp for when subscribed occurred, formatted as ISO 8601 when available." }, "next_payment": { "type": "string", "example": "2026-08-01T09:00:00+00:00", "format": "date-time", "description": "Next scheduled payment date for the subscription when available." }, "amount": { "type": "integer", "example": 49, "description": "Monetary amount in the currency shown on the same object." }, "total_paid_amount": { "type": "integer", "example": 98, "description": "Monetary amount in the currency shown on the same object." }, "gateway": { "type": "string", "example": "stripe", "description": "Payment gateway used for this checkout or billing flow.", "enum": [ "airwallex", "stripe", "paypal" ] } } }, "description": "Primary response payload for this request." }, "meta": { "type": "object", "additionalProperties": true, "properties": { "current_page": { "type": "integer", "example": 1, "description": "current page for meta." }, "last_page": { "type": "integer", "example": 1, "description": "last page for meta." }, "per_page": { "type": "integer", "example": 20, "description": "per page for meta." }, "total": { "type": "integer", "example": 1, "description": "Total number of records matching the current filters." }, "from": { "type": "integer", "example": 1, "description": "from for meta." }, "to": { "type": "integer", "example": 1, "description": "to for meta." } }, "description": "Pagination, filter, or response metadata for this request." } }, "required": [ "success", "data", "meta" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### POST /api/v1/subscriptions/{subscription_id}/cancel Operation: `cancelSubscription` Cancel Subscription Cancel Subscription. Use it to start checkouts, verify completion, manage saved payment methods, inspect invoices, and cancel or resume organization billing subscriptions. It applies the requested change and returns the updated resource, validation result, or action status needed for the next API step. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `subscription_id` in path (string, required): Public subscription reference returned by the API. #### Responses - **200**: Cancel Subscription succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "Subscription cancelled.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." } }, "required": [ "success", "message" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **404**: Resource not found. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### POST /api/v1/subscriptions/{subscription_id}/resume Operation: `resumeSubscription` Resume Subscription Resume Subscription. Use it to start checkouts, verify completion, manage saved payment methods, inspect invoices, and cancel or resume organization billing subscriptions. It applies the requested change and returns the updated resource, validation result, or action status needed for the next API step. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `subscription_id` in path (string, required): Public subscription reference returned by the API. #### Responses - **200**: Resume Subscription succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "Subscription resumed.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." } }, "required": [ "success", "message" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **404**: Resource not found. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### POST /api/v1/subscriptions/subscribe/{package_id}/checkout/airwallex Operation: `createAirwallexSubscriptionCheckout` Create Airwallex Subscription Checkout Create Airwallex Subscription Checkout. Use it to start checkouts, verify completion, manage saved payment methods, inspect invoices, and cancel or resume organization billing subscriptions. It applies the requested change and returns the updated resource, validation result, or action status needed for the next API step. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `package_id` in path (string, required): Public package reference returned by the API. #### Request body Request payload. Required. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success_url": { "type": "string", "example": "https://northstar-distribution.co.uk/billing/success", "format": "uri", "description": "Public URL returned for this resource or action." }, "cancel_url": { "type": "string", "example": "https://northstar-distribution.co.uk/billing/cancel", "format": "uri", "description": "Public URL returned for this resource or action." } }, "required": [ "success_url", "cancel_url" ] } ``` #### Responses - **200**: Create Airwallex Subscription Checkout succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "Checkout created.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." }, "data": { "type": "object", "additionalProperties": true, "properties": { "checkout_id": { "type": "string", "example": "39b189c1-8f8e-4df2-8632-176f87f791a1", "format": "uuid", "description": "Stable public checkout reference. Use this value in related endpoint paths and request bodies." }, "gateway": { "type": "string", "example": "airwallex", "description": "Payment gateway used for this checkout or billing flow.", "enum": [ "airwallex", "stripe", "paypal" ] }, "status": { "type": "string", "example": "pending", "description": "Current lifecycle status for this record." }, "redirect_url": { "type": "string", "example": "https://checkout.spacemedia-docs.invalid/session/docs-checkout-session", "format": "uri", "description": "Hosted checkout or management URL where the user should continue the flow." }, "embedded_checkout_token": { "type": "string", "example": "docs_invalid_embedded_checkout_token", "description": "Short-lived embedded checkout token. Treat this value as sensitive payment data and never log it or expose it in support tickets.", "format": "password", "x-sensitive": true }, "amount": { "type": "integer", "example": 49, "description": "Monetary amount in the currency shown on the same object." }, "currency": { "type": "string", "example": "GBP", "description": "ISO currency code for the amount shown on the same object." }, "expires_at": { "type": "string", "example": "2026-07-04T10:30:00+00:00", "format": "date-time", "description": "Timestamp for when expires occurred, formatted as ISO 8601 when available." } }, "description": "Primary response payload for this request." } }, "required": [ "success", "message", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **404**: Resource not found. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **422**: Validation failed for success_url. The request was not applied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### POST /api/v1/subscriptions/subscribe/{package_id}/checkout/paypal Operation: `createPaypalSubscriptionCheckout` Create PayPal Subscription Checkout Create PayPal Subscription Checkout. Use it to start checkouts, verify completion, manage saved payment methods, inspect invoices, and cancel or resume organization billing subscriptions. It applies the requested change and returns the updated resource, validation result, or action status needed for the next API step. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `package_id` in path (string, required): Public package reference returned by the API. #### Request body Request payload. Required. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success_url": { "type": "string", "example": "https://northstar-distribution.co.uk/billing/success", "format": "uri", "description": "Public URL returned for this resource or action." }, "cancel_url": { "type": "string", "example": "https://northstar-distribution.co.uk/billing/cancel", "format": "uri", "description": "Public URL returned for this resource or action." } }, "required": [ "success_url", "cancel_url" ] } ``` #### Responses - **200**: Create PayPal Subscription Checkout succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "Checkout created.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." }, "data": { "type": "object", "additionalProperties": true, "properties": { "checkout_id": { "type": "string", "example": "39b189c1-8f8e-4df2-8632-176f87f791a1", "format": "uuid", "description": "Stable public checkout reference. Use this value in related endpoint paths and request bodies." }, "gateway": { "type": "string", "example": "paypal", "description": "Payment gateway used for this checkout or billing flow.", "enum": [ "airwallex", "stripe", "paypal" ] }, "status": { "type": "string", "example": "pending", "description": "Current lifecycle status for this record." }, "redirect_url": { "type": "string", "example": "https://checkout.spacemedia-docs.invalid/session/docs-checkout-session", "format": "uri", "description": "Hosted checkout or management URL where the user should continue the flow." }, "amount": { "type": "integer", "example": 49, "description": "Monetary amount in the currency shown on the same object." }, "currency": { "type": "string", "example": "GBP", "description": "ISO currency code for the amount shown on the same object." }, "expires_at": { "type": "string", "example": "2026-07-04T10:30:00+00:00", "description": "Timestamp for when expires occurred, formatted as ISO 8601 when available." } }, "example": { "checkout_id": "39b189c1-8f8e-4df2-8632-176f87f791a1", "gateway": "paypal", "status": "pending", "redirect_url": "https://checkout.spacemedia-docs.invalid/session/docs-checkout-session", "amount": 49, "currency": "GBP", "expires_at": "2026-07-04T10:30:00+00:00" }, "description": "Primary response payload for this request." } }, "example": { "success": true, "message": "Checkout created.", "data": { "checkout_id": "39b189c1-8f8e-4df2-8632-176f87f791a1", "gateway": "paypal", "status": "pending", "redirect_url": "https://checkout.spacemedia-docs.invalid/session/docs-checkout-session", "amount": 49, "currency": "GBP", "expires_at": "2026-07-04T10:30:00+00:00" } }, "required": [ "success", "message", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **404**: Resource not found. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **422**: Validation failed for success_url. The request was not applied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### POST /api/v1/subscriptions/subscribe/{package_id}/checkout/stripe Operation: `createStripeSubscriptionCheckout` Create Stripe Subscription Checkout Create Stripe Subscription Checkout. Use it to start checkouts, verify completion, manage saved payment methods, inspect invoices, and cancel or resume organization billing subscriptions. It applies the requested change and returns the updated resource, validation result, or action status needed for the next API step. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `package_id` in path (string, required): Public package reference returned by the API. #### Request body Request payload. Required. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success_url": { "type": "string", "example": "https://northstar-distribution.co.uk/billing/success", "format": "uri", "description": "Public URL returned for this resource or action." }, "cancel_url": { "type": "string", "example": "https://northstar-distribution.co.uk/billing/cancel", "format": "uri", "description": "Public URL returned for this resource or action." } }, "required": [ "success_url", "cancel_url" ] } ``` #### Responses - **200**: Create Stripe Subscription Checkout succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "Checkout created.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." }, "data": { "type": "object", "additionalProperties": true, "properties": { "checkout_id": { "type": "string", "example": "39b189c1-8f8e-4df2-8632-176f87f791a1", "format": "uuid", "description": "Stable public checkout reference. Use this value in related endpoint paths and request bodies." }, "gateway": { "type": "string", "example": "stripe", "description": "Payment gateway used for this checkout or billing flow.", "enum": [ "airwallex", "stripe", "paypal" ] }, "status": { "type": "string", "example": "pending", "description": "Current lifecycle status for this record." }, "redirect_url": { "type": "string", "example": "https://checkout.spacemedia-docs.invalid/session/docs-checkout-session", "format": "uri", "description": "Hosted checkout or management URL where the user should continue the flow." }, "amount": { "type": "integer", "example": 49, "description": "Monetary amount in the currency shown on the same object." }, "currency": { "type": "string", "example": "GBP", "description": "ISO currency code for the amount shown on the same object." }, "expires_at": { "type": "string", "example": "2026-07-04T10:30:00+00:00", "description": "Timestamp for when expires occurred, formatted as ISO 8601 when available." } }, "example": { "checkout_id": "39b189c1-8f8e-4df2-8632-176f87f791a1", "gateway": "stripe", "status": "pending", "redirect_url": "https://checkout.spacemedia-docs.invalid/session/docs-checkout-session", "amount": 49, "currency": "GBP", "expires_at": "2026-07-04T10:30:00+00:00" }, "description": "Primary response payload for this request." } }, "example": { "success": true, "message": "Checkout created.", "data": { "checkout_id": "39b189c1-8f8e-4df2-8632-176f87f791a1", "gateway": "stripe", "status": "pending", "redirect_url": "https://checkout.spacemedia-docs.invalid/session/docs-checkout-session", "amount": 49, "currency": "GBP", "expires_at": "2026-07-04T10:30:00+00:00" } }, "required": [ "success", "message", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **404**: Resource not found. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **422**: Validation failed for success_url. The request was not applied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### POST /api/v1/subscriptions/subscribe/{package_id}/payment-verify Operation: `verifySubscriptionCheckout` Verify Subscription Checkout Verify a subscription checkout by checkout_id after payment completion. The response confirms whether the subscription was activated or updated. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `package_id` in path (string, required): Public package reference returned by the API. #### Request body Request payload. Required. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "checkout_id": { "type": "string", "example": "39b189c1-8f8e-4df2-8632-176f87f791a1", "format": "uuid", "description": "Stable public checkout reference. Use this value in related endpoint paths and request bodies." } }, "required": [ "checkout_id" ] } ``` #### Responses - **200**: Verify Subscription Checkout succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "Subscription checkout verified.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." }, "data": { "type": "object", "additionalProperties": true, "properties": { "subscription_id": { "type": "string", "example": "ad3095e4-4628-43d0-8e47-d8996c7daf0d", "format": "uuid", "description": "Stable public subscription reference. Use this value in related endpoint paths and request bodies." }, "status": { "type": "string", "example": "active", "description": "Current lifecycle status for this record." }, "is_active": { "type": "boolean", "example": true, "description": "Whether the subscription, plan, add-on, or resource is currently active." }, "package": { "type": "object", "additionalProperties": true, "properties": { "package_id": { "type": "string", "example": "f3e184c8-8b3a-45b8-9bcb-cc12f70826b6", "format": "uuid", "description": "Stable public package reference. Use this value in related endpoint paths and request bodies." }, "name": { "type": "string", "example": "Growth Distribution Monthly", "description": "Display name for this package." }, "type": { "type": "string", "example": "membership", "description": "Public type or role value for this item." }, "status": { "type": "string", "example": "published", "description": "Current lifecycle status for this record." }, "price": { "type": "integer", "example": 49, "description": "price for package." }, "currency": { "type": "string", "example": "GBP", "description": "ISO currency code for the amount shown on the same object." }, "royalty_percentage": { "type": "integer", "example": 85, "description": "royalty percentage for package." }, "artist_profile_limit": { "type": "integer", "example": 25, "description": "artist profile limit for package." }, "release_limit": { "type": "integer", "example": 50, "description": "release limit for package." }, "release_limit_cycle": { "type": "string", "example": "monthly", "description": "release limit cycle for package." }, "feature_list": { "type": "array", "items": { "type": "string", "example": "Unlimited team members" }, "description": "feature list for package." } }, "description": "Membership package attached to the subscription or checkout." }, "subscribed_at": { "type": "string", "example": "2026-06-01T09:00:00+00:00", "format": "date-time", "description": "Timestamp for when subscribed occurred, formatted as ISO 8601 when available." }, "next_payment": { "type": "string", "example": "2026-08-01T09:00:00+00:00", "format": "date-time", "description": "Next scheduled payment date for the subscription when available." }, "amount": { "type": "integer", "example": 49, "description": "Monetary amount in the currency shown on the same object." }, "total_paid_amount": { "type": "integer", "example": 98, "description": "Monetary amount in the currency shown on the same object." }, "gateway": { "type": "string", "example": "stripe", "description": "Payment gateway used for this checkout or billing flow.", "enum": [ "airwallex", "stripe", "paypal" ] } }, "description": "Primary response payload for this request." } }, "required": [ "success", "message", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **404**: Resource not found. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **422**: Validation failed for checkout_id. The request was not applied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ## Add-Ons Purchase, install, activate, deactivate, and uninstall organization add-ons with explicit status verification. ### POST /api/v1/addons/{addon_slug}/{addon_version}/activate Operation: `activateAddon` Activate Add-On Activate Add-On. Use it to install, activate, deactivate, uninstall, and purchase organization add-ons that are visible to the caller through normal account permissions. It applies the requested change and returns the updated resource, validation result, or action status needed for the next API step. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `addon_slug` in path (string, required): Add-on slug, for example release-smartlinks or members-management. - `addon_version` in path (string, required): Add-on version available to the organization. #### Responses - **200**: Activate Add-On succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "Add-on activate completed.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." }, "data": { "type": "object", "additionalProperties": true, "properties": { "license_id": { "type": "string", "example": "f05e3ae3-4b17-45bd-a22f-e33d715b3486", "format": "uuid", "description": "Stable public license reference. Use this value in related endpoint paths and request bodies." }, "addon_slug": { "type": "string", "example": "release-smartlinks", "description": "Public slug for the add-on, used in add-on checkout and lifecycle endpoint paths." }, "addon_version": { "type": "string", "example": "1.3.0", "description": "Version of the add-on being purchased or activated, matching a version available to the organization." }, "status": { "type": "string", "example": "active", "description": "Current lifecycle status for this record." }, "flow": { "type": "string", "example": "organization_install", "description": "Checkout or setup flow type returned to help the client choose hosted redirect or embedded handling." }, "installed": { "type": "boolean", "example": true, "description": "Whether the add-on is currently installed for the organization." }, "activated_at": { "type": "string", "example": "2026-07-04T10:15:00+00:00", "format": "date-time", "description": "Timestamp for when activated occurred, formatted as ISO 8601 when available." } }, "description": "Primary response payload for this request." } }, "required": [ "success", "message", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **404**: Resource not found. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### POST /api/v1/addons/{addon_slug}/{addon_version}/deactivate Operation: `deactivateAddon` Deactivate Add-On Deactivate Add-On. Use it to install, activate, deactivate, uninstall, and purchase organization add-ons that are visible to the caller through normal account permissions. It applies the requested change and returns the updated resource, validation result, or action status needed for the next API step. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `addon_slug` in path (string, required): Add-on slug, for example release-smartlinks or members-management. - `addon_version` in path (string, required): Add-on version available to the organization. #### Responses - **200**: Deactivate Add-On succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "Add-on deactivate completed.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." }, "data": { "type": "object", "additionalProperties": true, "properties": { "license_id": { "type": "string", "example": "f05e3ae3-4b17-45bd-a22f-e33d715b3486", "format": "uuid", "description": "Stable public license reference. Use this value in related endpoint paths and request bodies." }, "addon_slug": { "type": "string", "example": "release-smartlinks", "description": "Public slug for the add-on, used in add-on checkout and lifecycle endpoint paths." }, "addon_version": { "type": "string", "example": "1.3.0", "description": "Version of the add-on being purchased or activated, matching a version available to the organization." }, "status": { "type": "string", "example": "active", "description": "Current lifecycle status for this record." }, "flow": { "type": "string", "example": "organization_install", "description": "Checkout or setup flow type returned to help the client choose hosted redirect or embedded handling." }, "installed": { "type": "boolean", "example": true, "description": "Whether the add-on is currently installed for the organization." }, "activated_at": { "type": "string", "example": "2026-07-04T10:15:00+00:00", "format": "date-time", "description": "Timestamp for when activated occurred, formatted as ISO 8601 when available." } }, "description": "Primary response payload for this request." } }, "required": [ "success", "message", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **404**: Resource not found. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### POST /api/v1/addons/{addon_slug}/{addon_version}/install Operation: `installAddon` Install Add-On Install Add-On. Use it to install, activate, deactivate, uninstall, and purchase organization add-ons that are visible to the caller through normal account permissions. It applies the requested change and returns the updated resource, validation result, or action status needed for the next API step. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `addon_slug` in path (string, required): Add-on slug, for example release-smartlinks or members-management. - `addon_version` in path (string, required): Add-on version available to the organization. #### Responses - **200**: Install Add-On succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "Add-on install completed.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." }, "data": { "type": "object", "additionalProperties": true, "properties": { "license_id": { "type": "string", "example": "f05e3ae3-4b17-45bd-a22f-e33d715b3486", "format": "uuid", "description": "Stable public license reference. Use this value in related endpoint paths and request bodies." }, "addon_slug": { "type": "string", "example": "release-smartlinks", "description": "Public slug for the add-on, used in add-on checkout and lifecycle endpoint paths." }, "addon_version": { "type": "string", "example": "1.3.0", "description": "Version of the add-on being purchased or activated, matching a version available to the organization." }, "status": { "type": "string", "example": "active", "description": "Current lifecycle status for this record." }, "flow": { "type": "string", "example": "organization_install", "description": "Checkout or setup flow type returned to help the client choose hosted redirect or embedded handling." }, "installed": { "type": "boolean", "example": true, "description": "Whether the add-on is currently installed for the organization." }, "activated_at": { "type": "string", "example": "2026-07-04T10:15:00+00:00", "format": "date-time", "description": "Timestamp for when activated occurred, formatted as ISO 8601 when available." } }, "description": "Primary response payload for this request." } }, "required": [ "success", "message", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **404**: Resource not found. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### POST /api/v1/addons/{addon_slug}/{addon_version}/uninstall Operation: `uninstallAddon` Uninstall Add-On Uninstall Add-On. Use it to install, activate, deactivate, uninstall, and purchase organization add-ons that are visible to the caller through normal account permissions. It applies the requested change and returns the updated resource, validation result, or action status needed for the next API step. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `addon_slug` in path (string, required): Add-on slug, for example release-smartlinks or members-management. - `addon_version` in path (string, required): Add-on version available to the organization. #### Responses - **200**: Uninstall Add-On succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "Add-on uninstall completed.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." }, "data": { "type": "object", "additionalProperties": true, "properties": { "license_id": { "type": "string", "example": "f05e3ae3-4b17-45bd-a22f-e33d715b3486", "format": "uuid", "description": "Stable public license reference. Use this value in related endpoint paths and request bodies." }, "addon_slug": { "type": "string", "example": "release-smartlinks", "description": "Public slug for the add-on, used in add-on checkout and lifecycle endpoint paths." }, "addon_version": { "type": "string", "example": "1.3.0", "description": "Version of the add-on being purchased or activated, matching a version available to the organization." }, "status": { "type": "string", "example": "active", "description": "Current lifecycle status for this record." }, "flow": { "type": "string", "example": "organization_install", "description": "Checkout or setup flow type returned to help the client choose hosted redirect or embedded handling." }, "installed": { "type": "boolean", "example": true, "description": "Whether the add-on is currently installed for the organization." }, "activated_at": { "type": "string", "example": "2026-07-04T10:15:00+00:00", "format": "date-time", "description": "Timestamp for when activated occurred, formatted as ISO 8601 when available." } }, "description": "Primary response payload for this request." } }, "required": [ "success", "message", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **404**: Resource not found. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### POST /api/v1/addons/{addon_slug}/checkout Operation: `createAddonCheckout` Create Add-On Checkout Create a checkout for an organization add-on version and billing cycle. Store checkout_id locally and verify the checkout before enabling paid add-on behavior in your integration. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `addon_slug` in path (string, required): Add-on slug, for example release-smartlinks or members-management. #### Request body Request payload. Required. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "addon_version": { "type": "string", "example": "1.3.0", "description": "Version of the add-on being purchased or activated, matching a version available to the organization." }, "cycle": { "type": "string", "example": "monthly", "description": "Billing cycle requested for the add-on checkout, such as monthly or yearly when both are offered." }, "gateway": { "type": "string", "example": "airwallex", "description": "Payment gateway used for this checkout or billing flow.", "enum": [ "airwallex", "stripe", "paypal" ] }, "success_url": { "type": "string", "example": "https://northstar-distribution.co.uk/addons/release-smartlinks/success", "format": "uri", "description": "Public URL returned for this resource or action." }, "cancel_url": { "type": "string", "example": "https://northstar-distribution.co.uk/addons/release-smartlinks/cancel", "format": "uri", "description": "Public URL returned for this resource or action." } }, "required": [ "addon_version", "gateway" ] } ``` #### Responses - **200**: Create Add-On Checkout succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "Checkout created.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." }, "data": { "type": "object", "additionalProperties": true, "properties": { "license_id": { "type": "string", "example": "f05e3ae3-4b17-45bd-a22f-e33d715b3486", "format": "uuid", "description": "Stable public license reference. Use this value in related endpoint paths and request bodies." }, "addon_slug": { "type": "string", "example": "release-smartlinks", "description": "Public slug for the add-on, used in add-on checkout and lifecycle endpoint paths." }, "addon_version": { "type": "string", "example": "1.3.0", "description": "Version of the add-on being purchased or activated, matching a version available to the organization." }, "status": { "type": "string", "example": "active", "description": "Current lifecycle status for this record." }, "flow": { "type": "string", "example": "organization_install", "description": "Checkout or setup flow type returned to help the client choose hosted redirect or embedded handling." }, "installed": { "type": "boolean", "example": true, "description": "Whether the add-on is currently installed for the organization." }, "activated_at": { "type": "string", "example": "2026-07-04T10:15:00+00:00", "format": "date-time", "description": "Timestamp for when activated occurred, formatted as ISO 8601 when available." }, "checkout": { "type": "object", "additionalProperties": true, "properties": { "checkout_id": { "type": "string", "example": "39b189c1-8f8e-4df2-8632-176f87f791a1", "format": "uuid", "description": "Stable public checkout reference. Use this value in related endpoint paths and request bodies." }, "gateway": { "type": "string", "example": "airwallex", "description": "Payment gateway used for this checkout or billing flow.", "enum": [ "airwallex", "stripe", "paypal" ] }, "status": { "type": "string", "example": "pending", "description": "Current lifecycle status for this record." }, "redirect_url": { "type": "string", "example": "https://checkout.spacemedia-docs.invalid/session/docs-checkout-session", "format": "uri", "description": "Hosted checkout or management URL where the user should continue the flow." }, "embedded_checkout_token": { "type": "string", "example": "docs_invalid_embedded_checkout_token", "description": "Short-lived embedded checkout token. Treat this value as sensitive payment data and never log it or expose it in support tickets.", "format": "password", "x-sensitive": true }, "amount": { "type": "integer", "example": 49, "description": "Monetary amount in the currency shown on the same object." }, "currency": { "type": "string", "example": "GBP", "description": "ISO currency code for the amount shown on the same object." }, "expires_at": { "type": "string", "example": "2026-07-04T10:30:00+00:00", "format": "date-time", "description": "Timestamp for when expires occurred, formatted as ISO 8601 when available." } }, "description": "Checkout object containing the public checkout reference, gateway, status, and continuation fields." } }, "description": "Primary response payload for this request." } }, "required": [ "success", "message", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **404**: Resource not found. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **422**: Validation failed for addon_version. The request was not applied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### GET /api/v1/addons/checkout/{checkout_id}/status Operation: `getAddonCheckoutStatus` View Add-On Checkout Status Check an add-on checkout by checkout_id. Use this after the user returns from payment or after an embedded payment component reports completion. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `checkout_id` in path (string, required): Public checkout reference returned by the API. #### Responses - **200**: View Add-On Checkout Status succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "data": { "type": "object", "additionalProperties": true, "properties": { "checkout_id": { "type": "string", "example": "39b189c1-8f8e-4df2-8632-176f87f791a1", "format": "uuid", "description": "Stable public checkout reference. Use this value in related endpoint paths and request bodies." }, "addon_slug": { "type": "string", "example": "release-smartlinks", "description": "Public slug for the add-on, used in add-on checkout and lifecycle endpoint paths." }, "addon_version": { "type": "string", "example": "1.3.0", "description": "Version of the add-on being purchased or activated, matching a version available to the organization." }, "status": { "type": "string", "example": "succeeded", "description": "Current lifecycle status for this record." }, "installed": { "type": "boolean", "example": true, "description": "Whether the add-on is currently installed for the organization." }, "license_id": { "type": "string", "example": "f05e3ae3-4b17-45bd-a22f-e33d715b3486", "format": "uuid", "description": "Stable public license reference. Use this value in related endpoint paths and request bodies." } }, "description": "Primary response payload for this request." } }, "required": [ "success", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **404**: Resource not found. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ## Copyright Read copyright summaries and release results, inspect wallet activity, and create or verify wallet top-ups. ### GET /api/v1/copyright/releases Operation: `listCopyrightReleases` List Copyright Releases List releases with copyright check state visible to the organization. Use release_id values to inspect one release in detail. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `page` in query (integer): Page number to return. - `size` in query (integer): Number of records per page. #### Responses - **200**: List Copyright Releases succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "data": { "type": "array", "items": { "type": "object", "additionalProperties": true, "properties": { "release": { "type": "object", "additionalProperties": true, "properties": { "release_id": { "type": "string", "example": "b7a15d95-58f6-4f67-b5d1-89f4f5bfb4d8", "format": "uuid", "description": "Stable public release reference. Use this value in related endpoint paths and request bodies." }, "title": { "type": "string", "example": "Midnight Atlas", "description": "Catalog or content title shown in the dashboard and API responses." }, "status": { "type": "string", "example": "draft", "description": "Current lifecycle status for this record." } }, "description": "Release summary or nested release object connected to this workflow." }, "status": { "type": "string", "example": "needs_review", "description": "Current lifecycle status for this record." }, "checks": { "type": "array", "items": { "type": "object", "additionalProperties": true, "properties": { "copyright_check_id": { "type": "string", "example": "acr_midnight_atlas_20260704", "description": "Organization-facing copyright check reference for this release or track." }, "detection_service": { "type": "string", "example": "audio_fingerprint", "description": "Public label for the copyright detection service used for this check." }, "status": { "type": "string", "example": "needs_review", "description": "Current lifecycle status for this record." }, "matched_tracks": { "type": "integer", "example": 1, "description": "matched tracks for checks." } } }, "description": "Readiness, copyright, or validation checks returned for the release or workflow." }, "documents": { "type": "array", "items": { "type": "object", "additionalProperties": true, "properties": { "document_id": { "type": "string", "example": "a211d645-b1c8-43f7-8c7e-1b40adc2cc7c", "format": "uuid", "description": "Stable public document reference. Use this value in related endpoint paths and request bodies." }, "status": { "type": "string", "example": "requested", "description": "Current lifecycle status for this record." }, "reason": { "type": "string", "example": "Please upload proof of licensed sample clearance.", "description": "Reason attached to the document status or review item." } } }, "description": "Supporting documents attached to the release, track, or review workflow." } } }, "description": "Primary response payload for this request." }, "meta": { "type": "object", "additionalProperties": true, "properties": { "current_page": { "type": "integer", "example": 1, "description": "current page for meta." }, "last_page": { "type": "integer", "example": 1, "description": "last page for meta." }, "per_page": { "type": "integer", "example": 20, "description": "per page for meta." }, "total": { "type": "integer", "example": 1, "description": "Total number of records matching the current filters." }, "from": { "type": "integer", "example": 1, "description": "from for meta." }, "to": { "type": "integer", "example": 1, "description": "to for meta." } }, "description": "Pagination, filter, or response metadata for this request." } }, "required": [ "success", "data", "meta" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **422**: Validation failed for page. The request was not applied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### GET /api/v1/copyright/releases/{release_id} Operation: `getCopyrightRelease` View Copyright Release Return copyright check details for one release by release_id, including status, document state, and wallet-related context visible to the caller. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `release_id` in path (string, required): Public release reference returned by the API. #### Responses - **200**: View Copyright Release succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "data": { "type": "object", "additionalProperties": true, "properties": { "release": { "type": "object", "additionalProperties": true, "properties": { "release_id": { "type": "string", "example": "b7a15d95-58f6-4f67-b5d1-89f4f5bfb4d8", "format": "uuid", "description": "Stable public release reference. Use this value in related endpoint paths and request bodies." }, "title": { "type": "string", "example": "Midnight Atlas", "description": "Catalog or content title shown in the dashboard and API responses." }, "status": { "type": "string", "example": "draft", "description": "Current lifecycle status for this record." } }, "description": "Release summary or nested release object connected to this workflow." }, "status": { "type": "string", "example": "needs_review", "description": "Current lifecycle status for this record." }, "checks": { "type": "array", "items": { "type": "object", "additionalProperties": true, "properties": { "copyright_check_id": { "type": "string", "example": "acr_midnight_atlas_20260704", "description": "Organization-facing copyright check reference for this release or track." }, "detection_service": { "type": "string", "example": "audio_fingerprint", "description": "Public label for the copyright detection service used for this check." }, "status": { "type": "string", "example": "needs_review", "description": "Current lifecycle status for this record." }, "matched_tracks": { "type": "integer", "example": 1, "description": "matched tracks for checks." } } }, "description": "Readiness, copyright, or validation checks returned for the release or workflow." }, "documents": { "type": "array", "items": { "type": "object", "additionalProperties": true, "properties": { "document_id": { "type": "string", "example": "a211d645-b1c8-43f7-8c7e-1b40adc2cc7c", "format": "uuid", "description": "Stable public document reference. Use this value in related endpoint paths and request bodies." }, "status": { "type": "string", "example": "requested", "description": "Current lifecycle status for this record." }, "reason": { "type": "string", "example": "Please upload proof of licensed sample clearance.", "description": "Reason attached to the document status or review item." } } }, "description": "Supporting documents attached to the release, track, or review workflow." } }, "description": "Primary response payload for this request." } }, "required": [ "success", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **404**: Resource not found. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### GET /api/v1/copyright/statistics Operation: `getCopyrightStatistics` View Copyright Statistics Return aggregate copyright check statistics for the organization, including recent usage and release-level outcomes where available. Security: ```json [ { "BearerAuth": [] } ] ``` #### Responses - **200**: View Copyright Statistics succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "data": { "type": "object", "additionalProperties": true, "properties": { "wallet_id": { "type": "string", "example": "1899e9c2-6b45-4d13-aed4-7f070d810905", "format": "uuid", "description": "Stable public wallet reference. Use this value in related endpoint paths and request bodies." }, "balance": { "type": "integer", "example": 120, "description": "Current credit, wallet, or account balance shown in the response currency or unit." }, "currency": { "type": "string", "example": "GBP", "description": "ISO currency code for the amount shown on the same object." }, "releases": { "type": "object", "additionalProperties": true, "properties": { "total": { "type": "integer", "example": 4, "description": "Total number of records matching the current filters." }, "clear": { "type": "integer", "example": 3, "description": "clear for releases." }, "needs_review": { "type": "integer", "example": 1, "description": "needs review for releases." }, "blocked": { "type": "integer", "example": 0, "description": "blocked for releases." } }, "description": "Releases visible for the current organization and permission scope." }, "documents_requested": { "type": "integer", "example": 1, "description": "Whether the track currently requires supporting rights or copyright documentation before review can continue." }, "last_checked_at": { "type": "string", "example": "2026-07-04T10:15:00+00:00", "format": "date-time", "description": "Timestamp for when last checked occurred, formatted as ISO 8601 when available." }, "trend": { "type": "array", "items": { "type": "object", "additionalProperties": true, "properties": { "date": { "type": "string", "example": "2026-07-01", "format": "date", "description": "date for trend." }, "clear": { "type": "integer", "example": 2, "description": "clear for trend." }, "needs_review": { "type": "integer", "example": 1, "description": "needs review for trend." } } }, "description": "Trend values used for reporting, analytics, or wallet usage summaries." } }, "description": "Primary response payload for this request." } }, "required": [ "success", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### GET /api/v1/copyright/summary Operation: `getCopyrightSummary` View Copyright Summary Return copyright check availability, wallet summary, and release readiness counts for the organization. Use it to decide whether checks can be started or need more credits. Security: ```json [ { "BearerAuth": [] } ] ``` #### Responses - **200**: View Copyright Summary succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "data": { "type": "object", "additionalProperties": true, "properties": { "wallet_id": { "type": "string", "example": "1899e9c2-6b45-4d13-aed4-7f070d810905", "format": "uuid", "description": "Stable public wallet reference. Use this value in related endpoint paths and request bodies." }, "balance": { "type": "integer", "example": 120, "description": "Current credit, wallet, or account balance shown in the response currency or unit." }, "currency": { "type": "string", "example": "GBP", "description": "ISO currency code for the amount shown on the same object." }, "releases": { "type": "object", "additionalProperties": true, "properties": { "total": { "type": "integer", "example": 4, "description": "Total number of records matching the current filters." }, "clear": { "type": "integer", "example": 3, "description": "clear for releases." }, "needs_review": { "type": "integer", "example": 1, "description": "needs review for releases." }, "blocked": { "type": "integer", "example": 0, "description": "blocked for releases." } }, "description": "Releases visible for the current organization and permission scope." }, "documents_requested": { "type": "integer", "example": 1, "description": "Whether the track currently requires supporting rights or copyright documentation before review can continue." }, "last_checked_at": { "type": "string", "example": "2026-07-04T10:15:00+00:00", "format": "date-time", "description": "Timestamp for when last checked occurred, formatted as ISO 8601 when available." } }, "description": "Primary response payload for this request." } }, "required": [ "success", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### GET /api/v1/copyright/wallet Operation: `getCopyrightWallet` View Copyright Wallet Return current copyright wallet balance and credit package information visible to the organization. Use this before starting checks or purchasing credits. Security: ```json [ { "BearerAuth": [] } ] ``` #### Responses - **200**: View Copyright Wallet succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "data": { "type": "object", "additionalProperties": true, "properties": { "wallet_id": { "type": "string", "example": "1899e9c2-6b45-4d13-aed4-7f070d810905", "format": "uuid", "description": "Stable public wallet reference. Use this value in related endpoint paths and request bodies." }, "balance": { "type": "integer", "example": 120, "description": "Current credit, wallet, or account balance shown in the response currency or unit." }, "currency": { "type": "string", "example": "GBP", "description": "ISO currency code for the amount shown on the same object." }, "low_balance": { "type": "boolean", "example": false, "description": "Whether the wallet or credit balance is below the recommended threshold." } }, "description": "Primary response payload for this request." } }, "required": [ "success", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### POST /api/v1/copyright/wallet/top-up Operation: `createCopyrightWalletTopUp` Create Copyright Wallet Top-Up Create a checkout to add credits to the copyright wallet. Store checkout_id and verify the top-up before assuming new credits are available. Security: ```json [ { "BearerAuth": [] } ] ``` #### Request body Request payload. Required. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "currency": { "type": "string", "example": "GBP", "description": "ISO currency code for the amount shown on the same object." }, "package_code": { "type": "string", "example": "copyright_100", "description": "PACKAGE CODE code used for catalog, country, currency, or rights metadata." }, "success_url": { "type": "string", "example": "https://northstar-distribution.co.uk/copyright/top-up/success", "format": "uri", "description": "Public URL returned for this resource or action." }, "cancel_url": { "type": "string", "example": "https://northstar-distribution.co.uk/copyright/top-up/cancel", "format": "uri", "description": "Public URL returned for this resource or action." } }, "required": [ "currency", "package_code", "success_url", "cancel_url" ] } ``` #### Responses - **200**: Create Copyright Wallet Top-Up succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "Checkout created.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." }, "data": { "type": "object", "additionalProperties": true, "properties": { "top_up_id": { "type": "string", "example": "2b8a0b6b-bca0-4b7f-8049-672e9a9d2928", "format": "uuid", "description": "Stable public top up reference. Use this value in related endpoint paths and request bodies." }, "checkout_id": { "type": "string", "example": "39b189c1-8f8e-4df2-8632-176f87f791a1", "format": "uuid", "description": "Stable public checkout reference. Use this value in related endpoint paths and request bodies." }, "status": { "type": "string", "example": "pending", "description": "Current lifecycle status for this record." }, "quote": { "type": "object", "additionalProperties": true, "properties": { "credits": { "type": "integer", "example": 100, "description": "credits for quote." }, "amount": { "type": "integer", "example": 25, "description": "Monetary amount in the currency shown on the same object." }, "currency": { "type": "string", "example": "GBP", "description": "ISO currency code for the amount shown on the same object." } }, "description": "Quoted checkout or billing amount before the user confirms payment." }, "checkout": { "type": "object", "additionalProperties": true, "properties": { "checkout_id": { "type": "string", "example": "39b189c1-8f8e-4df2-8632-176f87f791a1", "format": "uuid", "description": "Stable public checkout reference. Use this value in related endpoint paths and request bodies." }, "gateway": { "type": "string", "example": "airwallex", "description": "Payment gateway used for this checkout or billing flow.", "enum": [ "airwallex", "stripe", "paypal" ] }, "status": { "type": "string", "example": "pending", "description": "Current lifecycle status for this record." }, "redirect_url": { "type": "string", "example": "https://checkout.spacemedia-docs.invalid/session/docs-checkout-session", "format": "uri", "description": "Hosted checkout or management URL where the user should continue the flow." }, "embedded_checkout_token": { "type": "string", "example": "docs_invalid_embedded_checkout_token", "description": "Short-lived embedded checkout token. Treat this value as sensitive payment data and never log it or expose it in support tickets.", "format": "password", "x-sensitive": true }, "amount": { "type": "integer", "example": 49, "description": "Monetary amount in the currency shown on the same object." }, "currency": { "type": "string", "example": "GBP", "description": "ISO currency code for the amount shown on the same object." }, "expires_at": { "type": "string", "example": "2026-07-04T10:30:00+00:00", "format": "date-time", "description": "Timestamp for when expires occurred, formatted as ISO 8601 when available." } }, "description": "Checkout object containing the public checkout reference, gateway, status, and continuation fields." } }, "description": "Primary response payload for this request." } }, "required": [ "success", "message", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **422**: Validation failed for currency. The request was not applied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### GET /api/v1/copyright/wallet/top-up/{checkout_id}/status Operation: `getCopyrightTopUpStatus` Check Copyright Wallet Top-Up Status Check a copyright wallet top-up by checkout_id. Use it after payment completion to confirm whether wallet credits were applied. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `checkout_id` in path (string, required): Checkout reference returned when the wallet top-up was created. #### Responses - **200**: Check Copyright Wallet Top-Up Status succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "data": { "type": "object", "additionalProperties": true, "properties": { "top_up_id": { "type": "string", "example": "2b8a0b6b-bca0-4b7f-8049-672e9a9d2928", "format": "uuid", "description": "Stable public top up reference. Use this value in related endpoint paths and request bodies." }, "status": { "type": "string", "example": "succeeded", "description": "Current lifecycle status for this record." }, "credits": { "type": "integer", "example": 100, "description": "Number of wallet or account credits available, used, or being purchased." }, "completed_at": { "type": "string", "example": "2026-07-04T10:15:00+00:00", "format": "date-time", "description": "Timestamp for when completed occurred, formatted as ISO 8601 when available." } }, "description": "Primary response payload for this request." } }, "required": [ "success", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **404**: Resource not found. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### GET /api/v1/copyright/wallet/top-ups Operation: `listCopyrightTopUps` List Copyright Top-Ups List copyright wallet top-up attempts visible to the caller. Use checkout_id values to verify or inspect specific top-up payment states. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `page` in query (integer): Page number to return. - `size` in query (integer): Number of records per page. #### Responses - **200**: List Copyright Top-Ups succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "data": { "type": "array", "items": { "type": "object", "additionalProperties": true, "properties": { "top_up_id": { "type": "string", "example": "2b8a0b6b-bca0-4b7f-8049-672e9a9d2928", "format": "uuid", "description": "Stable public top up reference. Use this value in related endpoint paths and request bodies." }, "checkout_id": { "type": "string", "example": "39b189c1-8f8e-4df2-8632-176f87f791a1", "format": "uuid", "description": "Stable public checkout reference. Use this value in related endpoint paths and request bodies." }, "status": { "type": "string", "example": "pending", "description": "Current lifecycle status for this record." }, "quote": { "type": "object", "additionalProperties": true, "properties": { "credits": { "type": "integer", "example": 100, "description": "credits for quote." }, "amount": { "type": "integer", "example": 25, "description": "Monetary amount in the currency shown on the same object." }, "currency": { "type": "string", "example": "GBP", "description": "ISO currency code for the amount shown on the same object." } }, "description": "Quoted checkout or billing amount before the user confirms payment." }, "checkout": { "type": "object", "additionalProperties": true, "properties": { "checkout_id": { "type": "string", "example": "39b189c1-8f8e-4df2-8632-176f87f791a1", "format": "uuid", "description": "Stable public checkout reference. Use this value in related endpoint paths and request bodies." }, "gateway": { "type": "string", "example": "airwallex", "description": "Payment gateway used for this checkout or billing flow.", "enum": [ "airwallex", "stripe", "paypal" ] }, "status": { "type": "string", "example": "pending", "description": "Current lifecycle status for this record." }, "redirect_url": { "type": "string", "example": "https://checkout.spacemedia-docs.invalid/session/docs-checkout-session", "format": "uri", "description": "Hosted checkout or management URL where the user should continue the flow." }, "embedded_checkout_token": { "type": "string", "example": "docs_invalid_embedded_checkout_token", "description": "Short-lived embedded checkout token. Treat this value as sensitive payment data and never log it or expose it in support tickets.", "format": "password", "x-sensitive": true }, "amount": { "type": "integer", "example": 49, "description": "Monetary amount in the currency shown on the same object." }, "currency": { "type": "string", "example": "GBP", "description": "ISO currency code for the amount shown on the same object." }, "expires_at": { "type": "string", "example": "2026-07-04T10:30:00+00:00", "format": "date-time", "description": "Timestamp for when expires occurred, formatted as ISO 8601 when available." } }, "description": "Checkout object containing the public checkout reference, gateway, status, and continuation fields." } } }, "description": "Primary response payload for this request." }, "meta": { "type": "object", "additionalProperties": true, "properties": { "current_page": { "type": "integer", "example": 1, "description": "current page for meta." }, "last_page": { "type": "integer", "example": 1, "description": "last page for meta." }, "per_page": { "type": "integer", "example": 20, "description": "per page for meta." }, "total": { "type": "integer", "example": 1, "description": "Total number of records matching the current filters." }, "from": { "type": "integer", "example": 1, "description": "from for meta." }, "to": { "type": "integer", "example": 1, "description": "to for meta." } }, "description": "Pagination, filter, or response metadata for this request." } }, "required": [ "success", "data", "meta" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **422**: Validation failed for page. The request was not applied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### GET /api/v1/copyright/wallet/transactions Operation: `listCopyrightWalletTransactions` List Copyright Wallet Transactions List wallet credit movements for copyright checks, including top-ups and usage. Use this to reconcile credit balance changes with release checks. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `page` in query (integer): Page number to return. - `size` in query (integer): Number of records per page. #### Responses - **200**: List Copyright Wallet Transactions succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "data": { "type": "array", "items": { "type": "object", "additionalProperties": true, "properties": { "wallet_transaction_id": { "type": "string", "example": "e6e8f7ed-bda5-4c5f-a461-3cbac9794516", "format": "uuid", "description": "Stable public wallet transaction reference. Use this value in related endpoint paths and request bodies." }, "type": { "type": "string", "example": "top_up", "description": "Public type or role value for this item." }, "credits": { "type": "integer", "example": 100, "description": "Number of wallet or account credits available, used, or being purchased." }, "amount": { "type": "integer", "example": 25, "description": "Monetary amount in the currency shown on the same object." }, "currency": { "type": "string", "example": "GBP", "description": "ISO currency code for the amount shown on the same object." }, "status": { "type": "string", "example": "completed", "description": "Current lifecycle status for this record." }, "created_at": { "type": "string", "example": "2026-07-04T09:30:00+00:00", "format": "date-time", "description": "Timestamp for when created occurred, formatted as ISO 8601 when available." } } }, "description": "Primary response payload for this request." }, "meta": { "type": "object", "additionalProperties": true, "properties": { "current_page": { "type": "integer", "example": 1, "description": "current page for meta." }, "last_page": { "type": "integer", "example": 1, "description": "last page for meta." }, "per_page": { "type": "integer", "example": 20, "description": "per page for meta." }, "total": { "type": "integer", "example": 1, "description": "Total number of records matching the current filters." }, "from": { "type": "integer", "example": 1, "description": "from for meta." }, "to": { "type": "integer", "example": 1, "description": "to for meta." } }, "description": "Pagination, filter, or response metadata for this request." } }, "required": [ "success", "data", "meta" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **422**: Validation failed for page. The request was not applied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ## Release Review Read organization-visible submitted, sent, and combined release review queues for operational monitoring. ### GET /api/v1/qc/releases/all Operation: `listOrganizationReleaseReviews` List Organization Release Reviews List release review records visible inside the authenticated organization. Use this organization-scoped queue to build review dashboards, filters, or status monitors for releases the caller is allowed to inspect. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `page` in query (integer): Page number to return. - `size` in query (integer): Number of records per page. #### Responses - **200**: List Organization Release Reviews succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "data": { "type": "array", "items": { "type": "object", "additionalProperties": true, "properties": { "status": { "type": "string", "example": "submitted", "description": "Current lifecycle status for this record." }, "delivery_status": { "type": "string", "example": "pending_review", "description": "Current delivery status shown to the organization." }, "delivery_simulated": { "type": "boolean", "example": false, "description": "True only when staging completed the delivery lifecycle locally without contacting a DSP or delivery partner." }, "submitted_at": { "type": "string", "example": "2026-07-04T09:30:00+00:00", "format": "date-time", "description": "Timestamp for when submitted occurred, formatted as ISO 8601 when available." }, "release": { "type": "object", "additionalProperties": true, "properties": { "release_id": { "type": "string", "example": "b7a15d95-58f6-4f67-b5d1-89f4f5bfb4d8", "format": "uuid", "description": "Stable public release reference. Use this value in related endpoint paths and request bodies." }, "title": { "type": "string", "example": "Midnight Atlas", "description": "Catalog or content title shown in the dashboard and API responses." }, "status": { "type": "string", "example": "draft", "description": "Current lifecycle status for this record." }, "format": { "type": "string", "example": "single", "description": "Release format, such as single, EP, or album." }, "label": { "type": "string", "example": "Night Shift Records", "description": "Label name attached to the release metadata." }, "genre": { "type": "string", "example": "Electronic", "description": "Primary release or track genre selected from supported values." }, "secondary_genre": { "type": "string", "example": "Ambient", "description": "Optional secondary genre used for more precise metadata." }, "language": { "type": "string", "example": "English", "description": "Primary language value used for profile, release, or track metadata." }, "explicit_content": { "type": "boolean", "example": false, "description": "Whether the release or track is marked as explicit." }, "upc_code": { "type": "string", "example": "5054429191012", "description": "UPC assigned to the release, or null when it has not been assigned yet." }, "reference_number": { "type": "string", "example": "NSD-2026-041", "description": "Human-readable catalog or billing reference shown in the dashboard." }, "scheduled_date": { "type": "string", "example": "2026-08-21", "format": "date", "description": "Scheduled release date used for delivery planning and catalog display." }, "original_release_date": { "type": "string", "example": "2026-08-21", "format": "date", "description": "Calendar date for original release." }, "copyright_detection_enabled": { "type": "boolean", "example": true, "description": "copyright detection enabled for release." }, "price_category": { "type": "string", "example": "mid", "description": "Release price tier or commercial category used for store delivery and billing decisions." }, "territories": { "type": "array", "items": { "type": "string", "example": "GB" }, "description": "Territory codes where the release or rights metadata should apply." }, "distribution": { "type": "array", "items": { "type": "object", "additionalProperties": true, "properties": { "channel": { "type": "string", "example": "spotify", "description": "Delivery channel or store identifier using public snake_case values." }, "status": { "type": "string", "example": "selected", "description": "Current lifecycle status for this record." } } }, "description": "Delivery destinations and their organization-visible status values." }, "cover_art": { "type": "string", "example": "https://assets.spacemedia-docs.invalid/releases/midnight-atlas/cover.jpg", "format": "uri", "description": "Public media URL or asset reference for the uploaded image." }, "track_count": { "type": "integer", "example": 1, "description": "Number of track records visible in this context." }, "artists": { "type": "array", "items": { "type": "object", "additionalProperties": false, "properties": { "artist_id": { "type": "string", "example": "6f209ac7-d82c-4c8f-9d3e-bfe39c0df802", "format": "uuid", "description": "Public artist reference returned by the artists API." }, "name": { "type": "string", "example": "Nova Vale", "description": "Display name for this artists." }, "type": { "type": "string", "example": "Primary Artist", "description": "Artist credit role for this release or track, such as Primary Artist or Featured Artist." } }, "required": [ "artist_id", "type" ] }, "description": "Artists credited or attached to this catalog record." }, "created_by": { "type": "object", "additionalProperties": true, "properties": { "user_id": { "type": "string", "example": "7d2d9f72-c0a2-4d4b-9b6d-7caa942b8a71", "format": "uuid", "description": "Stable public user reference. Use this value in related endpoint paths and request bodies." }, "name": { "type": "string", "example": "Maya Chen", "description": "Display name for this created_by." }, "email": { "type": "string", "example": "maya.chen@northstar-distribution.co.uk", "description": "Email address associated with the account, member, invitation, or beneficiary." } }, "description": "User that created the record when available to the current organization." }, "created_at": { "type": "string", "example": "2026-07-04T09:30:00+00:00", "format": "date-time", "description": "Timestamp for when created occurred, formatted as ISO 8601 when available." }, "updated_at": { "type": "string", "example": "2026-07-04T10:15:00+00:00", "format": "date-time", "description": "Timestamp for when updated occurred, formatted as ISO 8601 when available." } }, "description": "Release summary or nested release object connected to this workflow." } } }, "description": "Primary response payload for this request." }, "meta": { "type": "object", "additionalProperties": true, "properties": { "current_page": { "type": "integer", "example": 1, "description": "current page for meta." }, "last_page": { "type": "integer", "example": 1, "description": "last page for meta." }, "per_page": { "type": "integer", "example": 20, "description": "per page for meta." }, "total": { "type": "integer", "example": 1, "description": "Total number of records matching the current filters." }, "from": { "type": "integer", "example": 1, "description": "from for meta." }, "to": { "type": "integer", "example": 1, "description": "to for meta." } }, "description": "Pagination, filter, or response metadata for this request." } }, "required": [ "success", "data", "meta" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **422**: Validation failed for page. The request was not applied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### GET /api/v1/qc/releases/sent Operation: `listSentReviewReleases` List Sent Review Releases List releases sent onward after review. Use this queue to monitor delivery progress without exposing provider repair or operational controls. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `page` in query (integer): Page number to return. - `size` in query (integer): Number of records per page. #### Responses - **200**: List Sent Review Releases succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "data": { "type": "array", "items": { "type": "object", "additionalProperties": true, "properties": { "status": { "type": "string", "example": "sent", "description": "Current lifecycle status for this record." }, "delivery_status": { "type": "string", "example": "delivered", "description": "Current delivery status shown to the organization." }, "delivery_simulated": { "type": "boolean", "example": false, "description": "True only when staging completed the delivery lifecycle locally without contacting a DSP or delivery partner." }, "submitted_at": { "type": "string", "example": "2026-07-04T09:30:00+00:00", "format": "date-time", "description": "Timestamp for when submitted occurred, formatted as ISO 8601 when available." }, "release": { "type": "object", "additionalProperties": true, "properties": { "release_id": { "type": "string", "example": "b7a15d95-58f6-4f67-b5d1-89f4f5bfb4d8", "format": "uuid", "description": "Stable public release reference. Use this value in related endpoint paths and request bodies." }, "title": { "type": "string", "example": "Midnight Atlas", "description": "Catalog or content title shown in the dashboard and API responses." }, "status": { "type": "string", "example": "draft", "description": "Current lifecycle status for this record." }, "format": { "type": "string", "example": "single", "description": "Release format, such as single, EP, or album." }, "label": { "type": "string", "example": "Night Shift Records", "description": "Label name attached to the release metadata." }, "genre": { "type": "string", "example": "Electronic", "description": "Primary release or track genre selected from supported values." }, "secondary_genre": { "type": "string", "example": "Ambient", "description": "Optional secondary genre used for more precise metadata." }, "language": { "type": "string", "example": "English", "description": "Primary language value used for profile, release, or track metadata." }, "explicit_content": { "type": "boolean", "example": false, "description": "Whether the release or track is marked as explicit." }, "upc_code": { "type": "string", "example": "5054429191012", "description": "UPC assigned to the release, or null when it has not been assigned yet." }, "reference_number": { "type": "string", "example": "NSD-2026-041", "description": "Human-readable catalog or billing reference shown in the dashboard." }, "scheduled_date": { "type": "string", "example": "2026-08-21", "format": "date", "description": "Scheduled release date used for delivery planning and catalog display." }, "original_release_date": { "type": "string", "example": "2026-08-21", "format": "date", "description": "Calendar date for original release." }, "copyright_detection_enabled": { "type": "boolean", "example": true, "description": "copyright detection enabled for release." }, "price_category": { "type": "string", "example": "mid", "description": "Release price tier or commercial category used for store delivery and billing decisions." }, "territories": { "type": "array", "items": { "type": "string", "example": "GB" }, "description": "Territory codes where the release or rights metadata should apply." }, "distribution": { "type": "array", "items": { "type": "object", "additionalProperties": true, "properties": { "channel": { "type": "string", "example": "spotify", "description": "Delivery channel or store identifier using public snake_case values." }, "status": { "type": "string", "example": "selected", "description": "Current lifecycle status for this record." } } }, "description": "Delivery destinations and their organization-visible status values." }, "cover_art": { "type": "string", "example": "https://assets.spacemedia-docs.invalid/releases/midnight-atlas/cover.jpg", "format": "uri", "description": "Public media URL or asset reference for the uploaded image." }, "track_count": { "type": "integer", "example": 1, "description": "Number of track records visible in this context." }, "artists": { "type": "array", "items": { "type": "object", "additionalProperties": false, "properties": { "artist_id": { "type": "string", "example": "6f209ac7-d82c-4c8f-9d3e-bfe39c0df802", "format": "uuid", "description": "Public artist reference returned by the artists API." }, "name": { "type": "string", "example": "Nova Vale", "description": "Display name for this artists." }, "type": { "type": "string", "example": "Primary Artist", "description": "Artist credit role for this release or track, such as Primary Artist or Featured Artist." } }, "required": [ "artist_id", "type" ] }, "description": "Artists credited or attached to this catalog record." }, "created_by": { "type": "object", "additionalProperties": true, "properties": { "user_id": { "type": "string", "example": "7d2d9f72-c0a2-4d4b-9b6d-7caa942b8a71", "format": "uuid", "description": "Stable public user reference. Use this value in related endpoint paths and request bodies." }, "name": { "type": "string", "example": "Maya Chen", "description": "Display name for this created_by." }, "email": { "type": "string", "example": "maya.chen@northstar-distribution.co.uk", "description": "Email address associated with the account, member, invitation, or beneficiary." } }, "description": "User that created the record when available to the current organization." }, "created_at": { "type": "string", "example": "2026-07-04T09:30:00+00:00", "format": "date-time", "description": "Timestamp for when created occurred, formatted as ISO 8601 when available." }, "updated_at": { "type": "string", "example": "2026-07-04T10:15:00+00:00", "format": "date-time", "description": "Timestamp for when updated occurred, formatted as ISO 8601 when available." } }, "description": "Release summary or nested release object connected to this workflow." } } }, "description": "Primary response payload for this request." }, "meta": { "type": "object", "additionalProperties": true, "properties": { "current_page": { "type": "integer", "example": 1, "description": "current page for meta." }, "last_page": { "type": "integer", "example": 1, "description": "last page for meta." }, "per_page": { "type": "integer", "example": 20, "description": "per page for meta." }, "total": { "type": "integer", "example": 1, "description": "Total number of records matching the current filters." }, "from": { "type": "integer", "example": 1, "description": "from for meta." }, "to": { "type": "integer", "example": 1, "description": "to for meta." } }, "description": "Pagination, filter, or response metadata for this request." } }, "required": [ "success", "data", "meta" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **422**: Validation failed for page. The request was not applied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### GET /api/v1/qc/releases/submitted Operation: `listSubmittedReviewReleases` List Submitted Review Releases List releases that have been submitted for review and are visible to the caller. Use this queue to monitor review readiness and next actions for submitted catalog items. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `page` in query (integer): Page number to return. - `size` in query (integer): Number of records per page. #### Responses - **200**: List Submitted Review Releases succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "data": { "type": "array", "items": { "type": "object", "additionalProperties": true, "properties": { "status": { "type": "string", "example": "submitted", "description": "Current lifecycle status for this record." }, "delivery_status": { "type": "string", "example": "pending_review", "description": "Current delivery status shown to the organization." }, "delivery_simulated": { "type": "boolean", "example": false, "description": "True only when staging completed the delivery lifecycle locally without contacting a DSP or delivery partner." }, "submitted_at": { "type": "string", "example": "2026-07-04T09:30:00+00:00", "format": "date-time", "description": "Timestamp for when submitted occurred, formatted as ISO 8601 when available." }, "release": { "type": "object", "additionalProperties": true, "properties": { "release_id": { "type": "string", "example": "b7a15d95-58f6-4f67-b5d1-89f4f5bfb4d8", "format": "uuid", "description": "Stable public release reference. Use this value in related endpoint paths and request bodies." }, "title": { "type": "string", "example": "Midnight Atlas", "description": "Catalog or content title shown in the dashboard and API responses." }, "status": { "type": "string", "example": "draft", "description": "Current lifecycle status for this record." }, "format": { "type": "string", "example": "single", "description": "Release format, such as single, EP, or album." }, "label": { "type": "string", "example": "Night Shift Records", "description": "Label name attached to the release metadata." }, "genre": { "type": "string", "example": "Electronic", "description": "Primary release or track genre selected from supported values." }, "secondary_genre": { "type": "string", "example": "Ambient", "description": "Optional secondary genre used for more precise metadata." }, "language": { "type": "string", "example": "English", "description": "Primary language value used for profile, release, or track metadata." }, "explicit_content": { "type": "boolean", "example": false, "description": "Whether the release or track is marked as explicit." }, "upc_code": { "type": "string", "example": "5054429191012", "description": "UPC assigned to the release, or null when it has not been assigned yet." }, "reference_number": { "type": "string", "example": "NSD-2026-041", "description": "Human-readable catalog or billing reference shown in the dashboard." }, "scheduled_date": { "type": "string", "example": "2026-08-21", "format": "date", "description": "Scheduled release date used for delivery planning and catalog display." }, "original_release_date": { "type": "string", "example": "2026-08-21", "format": "date", "description": "Calendar date for original release." }, "copyright_detection_enabled": { "type": "boolean", "example": true, "description": "copyright detection enabled for release." }, "price_category": { "type": "string", "example": "mid", "description": "Release price tier or commercial category used for store delivery and billing decisions." }, "territories": { "type": "array", "items": { "type": "string", "example": "GB" }, "description": "Territory codes where the release or rights metadata should apply." }, "distribution": { "type": "array", "items": { "type": "object", "additionalProperties": true, "properties": { "channel": { "type": "string", "example": "spotify", "description": "Delivery channel or store identifier using public snake_case values." }, "status": { "type": "string", "example": "selected", "description": "Current lifecycle status for this record." } } }, "description": "Delivery destinations and their organization-visible status values." }, "cover_art": { "type": "string", "example": "https://assets.spacemedia-docs.invalid/releases/midnight-atlas/cover.jpg", "format": "uri", "description": "Public media URL or asset reference for the uploaded image." }, "track_count": { "type": "integer", "example": 1, "description": "Number of track records visible in this context." }, "artists": { "type": "array", "items": { "type": "object", "additionalProperties": false, "properties": { "artist_id": { "type": "string", "example": "6f209ac7-d82c-4c8f-9d3e-bfe39c0df802", "format": "uuid", "description": "Public artist reference returned by the artists API." }, "name": { "type": "string", "example": "Nova Vale", "description": "Display name for this artists." }, "type": { "type": "string", "example": "Primary Artist", "description": "Artist credit role for this release or track, such as Primary Artist or Featured Artist." } }, "required": [ "artist_id", "type" ] }, "description": "Artists credited or attached to this catalog record." }, "created_by": { "type": "object", "additionalProperties": true, "properties": { "user_id": { "type": "string", "example": "7d2d9f72-c0a2-4d4b-9b6d-7caa942b8a71", "format": "uuid", "description": "Stable public user reference. Use this value in related endpoint paths and request bodies." }, "name": { "type": "string", "example": "Maya Chen", "description": "Display name for this created_by." }, "email": { "type": "string", "example": "maya.chen@northstar-distribution.co.uk", "description": "Email address associated with the account, member, invitation, or beneficiary." } }, "description": "User that created the record when available to the current organization." }, "created_at": { "type": "string", "example": "2026-07-04T09:30:00+00:00", "format": "date-time", "description": "Timestamp for when created occurred, formatted as ISO 8601 when available." }, "updated_at": { "type": "string", "example": "2026-07-04T10:15:00+00:00", "format": "date-time", "description": "Timestamp for when updated occurred, formatted as ISO 8601 when available." } }, "description": "Release summary or nested release object connected to this workflow." } } }, "description": "Primary response payload for this request." }, "meta": { "type": "object", "additionalProperties": true, "properties": { "current_page": { "type": "integer", "example": 1, "description": "current page for meta." }, "last_page": { "type": "integer", "example": 1, "description": "last page for meta." }, "per_page": { "type": "integer", "example": 20, "description": "per page for meta." }, "total": { "type": "integer", "example": 1, "description": "Total number of records matching the current filters." }, "from": { "type": "integer", "example": 1, "description": "from for meta." }, "to": { "type": "integer", "example": 1, "description": "to for meta." } }, "description": "Pagination, filter, or response metadata for this request." } }, "required": [ "success", "data", "meta" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **422**: Validation failed for page. The request was not applied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ## Members Manage team members, invitations, roles, permissions, suspension, and access lifecycle within the organization. ### GET /api/v1/member-invitations Operation: `listMemberInvitations` List Member Invitations List Member Invitations. Use it to invite team members, manage roles, suspend access, resend invitations, and inspect the permission catalog for member administration. It returns public references and organization-visible fields only, so clients can safely use returned values in follow-up API calls. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `page` in query (integer): Page number to return. - `size` in query (integer): Number of records per page. #### Responses - **200**: List Member Invitations succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "data": { "type": "array", "items": { "type": "object", "additionalProperties": true, "properties": { "invitation_id": { "type": "string", "example": "9406c9cf-4880-43e6-a6db-59cc8c71502f", "format": "uuid", "description": "Stable public invitation reference. Use this value in related endpoint paths and request bodies." }, "email": { "type": "string", "example": "catalog.ops@northstar-distribution.co.uk", "description": "Email address associated with the account, member, invitation, or beneficiary." }, "role": { "type": "object", "additionalProperties": true, "properties": { "role_id": { "type": "string", "example": "c0f1c68c-7c2f-4954-b52c-9d7e5eb46d3e", "format": "uuid", "description": "Stable public role reference. Use this value in related endpoint paths and request bodies." }, "name": { "type": "string", "example": "Catalog Manager", "description": "Display name for this role." } }, "description": "Role assigned to the user or member, including its public role reference and display name when expanded." }, "status": { "type": "string", "example": "pending", "description": "Current lifecycle status for this record." }, "sent_at": { "type": "string", "example": "2026-07-04T09:30:00+00:00", "format": "date-time", "description": "Timestamp for when sent occurred, formatted as ISO 8601 when available." }, "expires_at": { "type": "string", "example": "2026-07-11T09:30:00+00:00", "format": "date-time", "description": "Timestamp for when expires occurred, formatted as ISO 8601 when available." } } }, "description": "Primary response payload for this request." }, "meta": { "type": "object", "additionalProperties": true, "properties": { "current_page": { "type": "integer", "example": 1, "description": "current page for meta." }, "last_page": { "type": "integer", "example": 1, "description": "last page for meta." }, "per_page": { "type": "integer", "example": 20, "description": "per page for meta." }, "total": { "type": "integer", "example": 1, "description": "Total number of records matching the current filters." }, "from": { "type": "integer", "example": 1, "description": "from for meta." }, "to": { "type": "integer", "example": 1, "description": "to for meta." } }, "description": "Pagination, filter, or response metadata for this request." } }, "required": [ "success", "data", "meta" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **422**: Validation failed for page. The request was not applied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### DELETE /api/v1/member-invitations/{invitation_id} Operation: `cancelMemberInvitation` Cancel Member Invitation Cancel Member Invitation. Use it to invite team members, manage roles, suspend access, resend invitations, and inspect the permission catalog for member administration. It removes, revokes, or cancels the target when permissions and resource state allow it, then returns a confirmation or policy error. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `invitation_id` in path (string, required): Public invitation reference returned by the API. #### Responses - **200**: Cancel Member Invitation succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "Invitation cancelled.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." } }, "required": [ "success", "message" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **404**: Resource not found. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### POST /api/v1/member-invitations/{invitation_id}/resend Operation: `resendMemberInvitation` Resend Member Invitation Resend Member Invitation. Use it to invite team members, manage roles, suspend access, resend invitations, and inspect the permission catalog for member administration. It applies the requested change and returns the updated resource, validation result, or action status needed for the next API step. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `invitation_id` in path (string, required): Public invitation reference returned by the API. #### Responses - **200**: Resend Member Invitation succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "Invitation resent.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." }, "data": { "type": "object", "additionalProperties": true, "properties": { "invitation_id": { "type": "string", "example": "9406c9cf-4880-43e6-a6db-59cc8c71502f", "format": "uuid", "description": "Stable public invitation reference. Use this value in related endpoint paths and request bodies." }, "email": { "type": "string", "example": "catalog.ops@northstar-distribution.co.uk", "description": "Email address associated with the account, member, invitation, or beneficiary." }, "role": { "type": "object", "additionalProperties": true, "properties": { "role_id": { "type": "string", "example": "c0f1c68c-7c2f-4954-b52c-9d7e5eb46d3e", "format": "uuid", "description": "Stable public role reference. Use this value in related endpoint paths and request bodies." }, "name": { "type": "string", "example": "Catalog Manager", "description": "Display name for this role." } }, "description": "Role assigned to the user or member, including its public role reference and display name when expanded." }, "status": { "type": "string", "example": "pending", "description": "Current lifecycle status for this record." }, "sent_at": { "type": "string", "example": "2026-07-04T09:30:00+00:00", "format": "date-time", "description": "Timestamp for when sent occurred, formatted as ISO 8601 when available." }, "expires_at": { "type": "string", "example": "2026-07-11T09:30:00+00:00", "format": "date-time", "description": "Timestamp for when expires occurred, formatted as ISO 8601 when available." } }, "description": "Primary response payload for this request." } }, "required": [ "success", "message", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **404**: Resource not found. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### GET /api/v1/member-permissions Operation: `listMemberPermissions` List Member Permissions List permission keys available for member roles in the organization. Use these keys when creating or updating role permissions. Security: ```json [ { "BearerAuth": [] } ] ``` #### Responses - **200**: List Member Permissions succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "data": { "type": "object", "additionalProperties": true, "properties": { "groups": { "type": "array", "items": { "type": "object", "additionalProperties": true, "properties": { "group": { "type": "string", "example": "Catalog", "description": "group for groups." }, "permissions": { "type": "array", "items": { "type": "string", "example": "view releases" }, "description": "Permission keys granted by this role or member assignment." } } }, "description": "Permission groups available when configuring member roles." } }, "description": "Primary response payload for this request." } }, "required": [ "success", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### GET /api/v1/member-roles Operation: `listMemberRoles` List Member Roles List Member Roles. Use it to invite team members, manage roles, suspend access, resend invitations, and inspect the permission catalog for member administration. It returns public references and organization-visible fields only, so clients can safely use returned values in follow-up API calls. Security: ```json [ { "BearerAuth": [] } ] ``` #### Responses - **200**: List Member Roles succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "data": { "type": "object", "additionalProperties": true, "properties": { "roles": { "type": "array", "items": { "type": "object", "additionalProperties": true, "properties": { "role_id": { "type": "string", "example": "c0f1c68c-7c2f-4954-b52c-9d7e5eb46d3e", "format": "uuid", "description": "Stable public role reference. Use this value in related endpoint paths and request bodies." }, "name": { "type": "string", "example": "Catalog Manager", "description": "Display name for this roles." }, "preset": { "type": "string", "example": "catalog_manager", "description": "Optional role template used to seed permissions before custom role edits are applied." }, "protected": { "type": "boolean", "example": false, "description": "protected for roles." }, "permissions": { "type": "array", "items": { "type": "string", "example": "view releases" }, "description": "Permission keys granted by this role or member assignment." } } }, "description": "Roles assigned to the user or member within the organization." } }, "description": "Primary response payload for this request." } }, "required": [ "success", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### POST /api/v1/member-roles Operation: `createMemberRole` Create Member Role Create a custom member role from a name and optional preset. Use the returned role_id when inviting or updating members. Security: ```json [ { "BearerAuth": [] } ] ``` #### Request body Request payload. Required. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "name": { "type": "string", "example": "Release Coordinator", "description": "Display name for this request body." }, "preset": { "type": "string", "example": "release_manager", "description": "Optional role template used to seed permissions before custom role edits are applied." } }, "required": [ "name" ] } ``` #### Responses - **201**: Create Member Role created the resource and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "Role created.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." }, "data": { "type": "object", "additionalProperties": true, "properties": { "role_id": { "type": "string", "example": "0c6f8128-7795-4974-88ae-9873d3b57df7", "format": "uuid", "description": "Stable public role reference. Use this value in related endpoint paths and request bodies." }, "name": { "type": "string", "example": "Release Coordinator", "description": "Display name for this data." }, "preset": { "type": "string", "example": "catalog_manager", "description": "Optional role template used to seed permissions before custom role edits are applied." }, "protected": { "type": "boolean", "example": false, "description": "Whether the role or setting is protected from organization-level edits." }, "permissions": { "type": "array", "items": { "type": "string", "example": "view releases" }, "description": "Permission keys granted by this role or member assignment." } }, "description": "Primary response payload for this request." } }, "required": [ "success", "message", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **422**: Validation failed for name. The request was not applied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### PATCH /api/v1/member-roles/{role_id} Operation: `updateMemberRole` Update Member Role Update Member Role. Use it to invite team members, manage roles, suspend access, resend invitations, and inspect the permission catalog for member administration. It updates only the submitted fields for the target resource and returns the new state using public reference fields. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `role_id` in path (string, required): Public role reference returned by the API. #### Request body Request payload. Required. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "name": { "type": "string", "example": "Senior Catalog Manager", "description": "Display name for this request body." } }, "required": [ "name" ] } ``` #### Responses - **200**: Update Member Role succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "Role updated.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." }, "data": { "type": "object", "additionalProperties": true, "properties": { "role_id": { "type": "string", "example": "c0f1c68c-7c2f-4954-b52c-9d7e5eb46d3e", "format": "uuid", "description": "Stable public role reference. Use this value in related endpoint paths and request bodies." }, "name": { "type": "string", "example": "Senior Catalog Manager", "description": "Display name for this data." }, "preset": { "type": "string", "example": "catalog_manager", "description": "Optional role template used to seed permissions before custom role edits are applied." }, "protected": { "type": "boolean", "example": false, "description": "Whether the role or setting is protected from organization-level edits." }, "permissions": { "type": "array", "items": { "type": "string", "example": "view releases" }, "description": "Permission keys granted by this role or member assignment." } }, "description": "Primary response payload for this request." } }, "required": [ "success", "message", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **404**: Resource not found. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **422**: Validation failed for name. The request was not applied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### POST /api/v1/member-roles/{role_id}/permissions Operation: `updateMemberRolePermissions` Update Member Role Permissions Replace the permission keys assigned to a member role by role_id. Use the member permissions endpoint to discover valid permission keys first. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `role_id` in path (string, required): Public role reference returned by the API. #### Request body Request payload. Required. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "permissions": { "type": "array", "items": { "type": "string", "example": "view releases" }, "description": "Permission keys granted by this role or member assignment." } }, "required": [ "permissions" ] } ``` #### Responses - **200**: Update Member Role Permissions succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "Role permissions updated.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." }, "data": { "type": "object", "additionalProperties": true, "properties": { "role_id": { "type": "string", "example": "c0f1c68c-7c2f-4954-b52c-9d7e5eb46d3e", "format": "uuid", "description": "Stable public role reference. Use this value in related endpoint paths and request bodies." }, "name": { "type": "string", "example": "Catalog Manager", "description": "Display name for this data." }, "preset": { "type": "string", "example": "catalog_manager", "description": "Optional role template used to seed permissions before custom role edits are applied." }, "protected": { "type": "boolean", "example": false, "description": "Whether the role or setting is protected from organization-level edits." }, "permissions": { "type": "array", "items": { "type": "string", "example": "view releases" }, "description": "Permission keys granted by this role or member assignment." } }, "description": "Primary response payload for this request." } }, "required": [ "success", "message", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **404**: Resource not found. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **422**: Validation failed for permissions. The request was not applied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### GET /api/v1/members Operation: `listMembers` List Members List Members. Use it to invite team members, manage roles, suspend access, resend invitations, and inspect the permission catalog for member administration. It returns public references and organization-visible fields only, so clients can safely use returned values in follow-up API calls. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `search` in query (string): Search term for matching visible records. - `page` in query (integer): Page number to return. - `size` in query (integer): Number of records per page. - `sort` in query (string): Sort direction for creation date. #### Responses - **200**: List Members succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "data": { "type": "array", "items": { "type": "object", "additionalProperties": true, "properties": { "member_id": { "type": "string", "example": "54dbefc4-49b2-4b18-9945-0921fd07a9fd", "format": "uuid", "description": "Stable public member reference for member-management endpoints. Store and use member_id when reading, updating, suspending, unsuspending, or removing a team member." }, "first_name": { "type": "string", "example": "Eli", "description": "Given name for the user or member profile." }, "last_name": { "type": "string", "example": "Brooks", "description": "Family name for the user or member profile." }, "name": { "type": "string", "example": "Eli Brooks", "description": "Display name for this data." }, "email": { "type": "string", "example": "eli.brooks@northstar-distribution.co.uk", "description": "Email address associated with the account, member, invitation, or beneficiary." }, "status": { "type": "string", "example": "active", "description": "Current lifecycle status for this record." }, "role": { "type": "object", "additionalProperties": true, "properties": { "role_id": { "type": "string", "example": "c0f1c68c-7c2f-4954-b52c-9d7e5eb46d3e", "format": "uuid", "description": "Stable public role reference. Use this value in related endpoint paths and request bodies." }, "name": { "type": "string", "example": "Catalog Manager", "description": "Display name for this role." } }, "description": "Role assigned to the user or member, including its public role reference and display name when expanded." }, "permissions": { "type": "array", "items": { "type": "string", "example": "view releases" }, "description": "Permission keys granted by this role or member assignment." }, "is_suspended": { "type": "boolean", "example": false, "description": "Whether organization access is currently suspended for this account." }, "invited_at": { "type": "string", "example": "2026-07-01T12:00:00+00:00", "format": "date-time", "description": "Timestamp for when invited occurred, formatted as ISO 8601 when available." }, "accepted_at": { "type": "string", "example": "2026-07-02T09:05:00+00:00", "format": "date-time", "description": "Timestamp for when accepted occurred, formatted as ISO 8601 when available." } } }, "description": "Primary response payload for this request." }, "meta": { "type": "object", "additionalProperties": true, "properties": { "current_page": { "type": "integer", "example": 1, "description": "current page for meta." }, "last_page": { "type": "integer", "example": 1, "description": "last page for meta." }, "per_page": { "type": "integer", "example": 20, "description": "per page for meta." }, "total": { "type": "integer", "example": 1, "description": "Total number of records matching the current filters." }, "from": { "type": "integer", "example": 1, "description": "from for meta." }, "to": { "type": "integer", "example": 1, "description": "to for meta." } }, "description": "Pagination, filter, or response metadata for this request." } }, "required": [ "success", "data", "meta" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **422**: Validation failed for search. The request was not applied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### GET /api/v1/members/{member_id} Operation: `getMember` Get Member Get Member. Use it to invite team members, manage roles, suspend access, resend invitations, and inspect the permission catalog for member administration. It returns public references and organization-visible fields only, so clients can safely use returned values in follow-up API calls. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `member_id` in path (string, required): Public member reference returned by the API. #### Responses - **200**: Get Member succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "data": { "type": "object", "additionalProperties": true, "properties": { "member_id": { "type": "string", "example": "54dbefc4-49b2-4b18-9945-0921fd07a9fd", "format": "uuid", "description": "Stable public member reference for member-management endpoints. Store and use member_id when reading, updating, suspending, unsuspending, or removing a team member." }, "first_name": { "type": "string", "example": "Eli", "description": "Given name for the user or member profile." }, "last_name": { "type": "string", "example": "Brooks", "description": "Family name for the user or member profile." }, "name": { "type": "string", "example": "Eli Brooks", "description": "Display name for this data." }, "email": { "type": "string", "example": "eli.brooks@northstar-distribution.co.uk", "description": "Email address associated with the account, member, invitation, or beneficiary." }, "status": { "type": "string", "example": "active", "description": "Current lifecycle status for this record." }, "role": { "type": "object", "additionalProperties": true, "properties": { "role_id": { "type": "string", "example": "c0f1c68c-7c2f-4954-b52c-9d7e5eb46d3e", "format": "uuid", "description": "Stable public role reference. Use this value in related endpoint paths and request bodies." }, "name": { "type": "string", "example": "Catalog Manager", "description": "Display name for this role." } }, "description": "Role assigned to the user or member, including its public role reference and display name when expanded." }, "permissions": { "type": "array", "items": { "type": "string", "example": "view releases" }, "description": "Permission keys granted by this role or member assignment." }, "is_suspended": { "type": "boolean", "example": false, "description": "Whether organization access is currently suspended for this account." }, "invited_at": { "type": "string", "example": "2026-07-01T12:00:00+00:00", "format": "date-time", "description": "Timestamp for when invited occurred, formatted as ISO 8601 when available." }, "accepted_at": { "type": "string", "example": "2026-07-02T09:05:00+00:00", "format": "date-time", "description": "Timestamp for when accepted occurred, formatted as ISO 8601 when available." } }, "description": "Primary response payload for this request." } }, "required": [ "success", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **404**: Resource not found. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### PATCH /api/v1/members/{member_id} Operation: `updateMember` Update Member Update a member profile or role by member_id. Use role_id from member roles and avoid changing access state here, because suspend and unsuspend have dedicated endpoints. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `member_id` in path (string, required): Public member reference returned by the API. #### Request body Request payload. Required. **application/json** ```json { "type": "object", "additionalProperties": false, "properties": { "first_name": { "type": "string", "example": "Eli", "description": "Given name for the user or member profile." }, "last_name": { "type": "string", "example": "Brooks", "description": "Family name for the user or member profile." }, "role_id": { "type": "string", "example": "c0f1c68c-7c2f-4954-b52c-9d7e5eb46d3e", "format": "uuid", "description": "Public role reference from the member roles endpoint. Include it only when changing the member role." } }, "minProperties": 1, "description": "Send at least one profile or role field to update." } ``` #### Responses - **200**: Update Member succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "Member updated.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." }, "data": { "type": "object", "additionalProperties": true, "properties": { "member_id": { "type": "string", "example": "54dbefc4-49b2-4b18-9945-0921fd07a9fd", "format": "uuid", "description": "Stable public member reference for member-management endpoints. Store and use member_id when reading, updating, suspending, unsuspending, or removing a team member." }, "first_name": { "type": "string", "example": "Eli", "description": "Given name for the user or member profile." }, "last_name": { "type": "string", "example": "Brooks", "description": "Family name for the user or member profile." }, "name": { "type": "string", "example": "Eli Brooks", "description": "Display name for this data." }, "email": { "type": "string", "example": "eli.brooks@northstar-distribution.co.uk", "description": "Email address associated with the account, member, invitation, or beneficiary." }, "status": { "type": "string", "example": "active", "description": "Current lifecycle status for this record." }, "role": { "type": "object", "additionalProperties": true, "properties": { "role_id": { "type": "string", "example": "c0f1c68c-7c2f-4954-b52c-9d7e5eb46d3e", "format": "uuid", "description": "Stable public role reference. Use this value in related endpoint paths and request bodies." }, "name": { "type": "string", "example": "Catalog Manager", "description": "Display name for this role." } }, "description": "Role assigned to the user or member, including its public role reference and display name when expanded." }, "permissions": { "type": "array", "items": { "type": "string", "example": "view releases" }, "description": "Permission keys granted by this role or member assignment." }, "is_suspended": { "type": "boolean", "example": false, "description": "Whether organization access is currently suspended for this account." }, "invited_at": { "type": "string", "example": "2026-07-01T12:00:00+00:00", "format": "date-time", "description": "Timestamp for when invited occurred, formatted as ISO 8601 when available." }, "accepted_at": { "type": "string", "example": "2026-07-02T09:05:00+00:00", "format": "date-time", "description": "Timestamp for when accepted occurred, formatted as ISO 8601 when available." } }, "description": "Primary response payload for this request." } }, "required": [ "success", "message", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **404**: Resource not found. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **422**: Validation failed for first_name. The request was not applied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### DELETE /api/v1/members/{member_id} Operation: `removeMember` Remove Member Remove Member. Use it to invite team members, manage roles, suspend access, resend invitations, and inspect the permission catalog for member administration. It removes, revokes, or cancels the target when permissions and resource state allow it, then returns a confirmation or policy error. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `member_id` in path (string, required): Public member reference returned by the API. #### Responses - **200**: Remove Member succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "Member removed.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." } }, "required": [ "success", "message" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **404**: Resource not found. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### POST /api/v1/members/{member_id}/suspend Operation: `suspendMember` Suspend Member Suspend Member. Use it to invite team members, manage roles, suspend access, resend invitations, and inspect the permission catalog for member administration. It applies the requested change and returns the updated resource, validation result, or action status needed for the next API step. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `member_id` in path (string, required): Public member reference returned by the API. #### Responses - **200**: Suspend Member succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "Member suspended.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." } }, "required": [ "success", "message" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **404**: Resource not found. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### POST /api/v1/members/{member_id}/unsuspend Operation: `unsuspendMember` Unsuspend Member Unsuspend Member. Use it to invite team members, manage roles, suspend access, resend invitations, and inspect the permission catalog for member administration. It applies the requested change and returns the updated resource, validation result, or action status needed for the next API step. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `member_id` in path (string, required): Public member reference returned by the API. #### Responses - **200**: Unsuspend Member succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "Member unsuspended.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." } }, "required": [ "success", "message" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **404**: Resource not found. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### POST /api/v1/members/invite Operation: `inviteMembers` Invite Members Invite one or more team members by email. Assign either a role_id from member roles or a preset key returned by the member permissions endpoint. Invitations are scoped to the authenticated organization. Security: ```json [ { "BearerAuth": [] } ] ``` #### Request body Request payload. Required. **application/json** ```json { "type": "object", "additionalProperties": false, "properties": { "emails": { "type": "array", "minItems": 1, "maxItems": 50, "items": { "type": "string", "format": "email", "example": "eli.brooks@northstar-distribution.co.uk" }, "description": "Email addresses to invite into the organization as team members." }, "role_id": { "type": "string", "format": "uuid", "example": "c0f1c68c-7c2f-4954-b52c-9d7e5eb46d3e", "description": "Public role reference from the member roles endpoint. Required when preset is not supplied." }, "preset": { "type": "string", "example": "label_manager", "description": "Preset key from the member permissions endpoint. Required when role_id is not supplied." }, "expires_in_days": { "type": "integer", "minimum": 1, "maximum": 90, "example": 14, "description": "Number of days before the invitation expires." } }, "required": [ "emails" ], "oneOf": [ { "required": [ "role_id" ] }, { "required": [ "preset" ] } ] } ``` #### Responses - **201**: Invite Members created the resource and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "Member invitations sent.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." }, "data": { "type": "object", "additionalProperties": true, "properties": { "members": { "type": "array", "items": { "type": "object", "additionalProperties": true, "properties": { "member_id": { "type": "string", "example": "54dbefc4-49b2-4b18-9945-0921fd07a9fd", "format": "uuid", "description": "Stable public member reference for member-management endpoints. Store and use member_id when reading, updating, suspending, unsuspending, or removing a team member." }, "first_name": { "type": "string", "example": "Eli", "description": "Given name for the user or member profile." }, "last_name": { "type": "string", "example": "Brooks", "description": "Family name for the user or member profile." }, "name": { "type": "string", "example": "Eli Brooks", "description": "Display name for this members." }, "email": { "type": "string", "example": "eli.brooks@northstar-distribution.co.uk", "description": "Email address associated with the account, member, invitation, or beneficiary." }, "status": { "type": "string", "example": "active", "description": "Current lifecycle status for this record." }, "role": { "type": "object", "additionalProperties": true, "properties": { "role_id": { "type": "string", "example": "c0f1c68c-7c2f-4954-b52c-9d7e5eb46d3e", "format": "uuid", "description": "Stable public role reference. Use this value in related endpoint paths and request bodies." }, "name": { "type": "string", "example": "Catalog Manager", "description": "Display name for this role." } }, "description": "role for members." }, "permissions": { "type": "array", "items": { "type": "string", "example": "view releases" }, "description": "Permission keys granted by this role or member assignment." }, "is_suspended": { "type": "boolean", "example": false, "description": "Whether organization access is currently suspended for this account." }, "invited_at": { "type": "string", "example": "2026-07-01T12:00:00+00:00", "format": "date-time", "description": "Timestamp for when invited occurred, formatted as ISO 8601 when available." }, "accepted_at": { "type": "string", "example": "2026-07-02T09:05:00+00:00", "format": "date-time", "description": "Timestamp for when accepted occurred, formatted as ISO 8601 when available." } } }, "description": "Array of member invitations containing recipient details and role references for each invited person." }, "invitations": { "type": "array", "items": { "type": "object", "additionalProperties": true, "properties": { "invitation_id": { "type": "string", "example": "9406c9cf-4880-43e6-a6db-59cc8c71502f", "format": "uuid", "description": "Stable public invitation reference. Use this value in related endpoint paths and request bodies." }, "email": { "type": "string", "example": "catalog.ops@northstar-distribution.co.uk", "description": "Email address associated with the account, member, invitation, or beneficiary." }, "role": { "type": "object", "additionalProperties": true, "properties": { "role_id": { "type": "string", "example": "c0f1c68c-7c2f-4954-b52c-9d7e5eb46d3e", "format": "uuid", "description": "Stable public role reference. Use this value in related endpoint paths and request bodies." }, "name": { "type": "string", "example": "Catalog Manager", "description": "Display name for this role." } }, "description": "role for invitations." }, "status": { "type": "string", "example": "pending", "description": "Current lifecycle status for this record." }, "sent_at": { "type": "string", "example": "2026-07-04T09:30:00+00:00", "format": "date-time", "description": "Timestamp for when sent occurred, formatted as ISO 8601 when available." }, "expires_at": { "type": "string", "example": "2026-07-11T09:30:00+00:00", "format": "date-time", "description": "Timestamp for when expires occurred, formatted as ISO 8601 when available." } } }, "description": "Pending member invitations visible to the organization." } }, "description": "Primary response payload for this request." } }, "required": [ "success", "message", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **422**: Validation failed for members. The request was not applied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ## Smartlinks Create and manage release smartlinks, destination links, preferences, synchronization, publication status, and analytics. ### GET /api/v1/smartlinks Operation: `listSmartlinks` List Smartlinks List Smartlinks. Use it to create and maintain release landing pages, DSP destinations, analytics visibility, and personal or organization smartlink preferences. It returns public references and organization-visible fields only, so clients can safely use returned values in follow-up API calls. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `search` in query (string): Search term for matching visible records. - `page` in query (integer): Page number to return. - `size` in query (integer): Number of records per page. - `sort` in query (string): Sort direction for creation date. #### Responses - **200**: List Smartlinks succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "data": { "type": "array", "items": { "type": "object", "additionalProperties": true, "properties": { "smartlink_id": { "type": "string", "example": "1fdf8564-81f7-4607-9c8b-154b62db8d5f", "format": "uuid", "description": "Stable public smartlink reference. Use this value in related endpoint paths and request bodies." }, "release": { "type": "object", "additionalProperties": true, "properties": { "release_id": { "type": "string", "example": "b7a15d95-58f6-4f67-b5d1-89f4f5bfb4d8", "format": "uuid", "description": "Stable public release reference. Use this value in related endpoint paths and request bodies." }, "title": { "type": "string", "example": "Midnight Atlas", "description": "Catalog or content title shown in the dashboard and API responses." }, "status": { "type": "string", "example": "draft", "description": "Current lifecycle status for this record." } }, "description": "Release summary or nested release object connected to this workflow." }, "slug": { "type": "string", "example": "nova-vale-midnight-atlas", "description": "URL-safe slug used for public links or add-on references." }, "title": { "type": "string", "example": "Midnight Atlas", "description": "Catalog or content title shown in the dashboard and API responses." }, "status": { "type": "string", "example": "published", "description": "Current lifecycle status for this record." }, "public_url": { "type": "string", "example": "https://links.northstar-distribution.co.uk/nova-vale-midnight-atlas", "format": "uri", "description": "Public URL returned for this resource or action." }, "destinations": { "type": "array", "items": { "type": "object", "additionalProperties": false, "properties": { "platform": { "type": "string", "example": "spotify", "description": "Streaming platform or destination key, such as spotify, apple_music, youtube_music, or deezer." }, "url": { "type": "string", "example": "https://open.spotify.com/album/4Gj9kL2mN8rT6bY1xQvP3z", "format": "uri", "description": "Public URL returned for this resource or action." }, "enabled": { "type": "boolean", "example": true, "description": "Whether this option or destination is currently enabled." } }, "required": [ "platform", "url" ] }, "description": "DSP and landing-page destination objects shown on the smartlink." }, "clicks": { "type": "integer", "example": 1840, "description": "Number of recorded smartlink clicks for the selected period or destination." }, "conversion_rate": { "type": "number", "example": 0.18, "description": "Percentage of visitors who clicked through or completed the measured smartlink action." }, "updated_at": { "type": "string", "example": "2026-07-04T10:15:00+00:00", "format": "date-time", "description": "Timestamp for when updated occurred, formatted as ISO 8601 when available." } } }, "description": "Primary response payload for this request." }, "meta": { "type": "object", "additionalProperties": true, "properties": { "current_page": { "type": "integer", "example": 1, "description": "current page for meta." }, "last_page": { "type": "integer", "example": 1, "description": "last page for meta." }, "per_page": { "type": "integer", "example": 20, "description": "per page for meta." }, "total": { "type": "integer", "example": 1, "description": "Total number of records matching the current filters." }, "from": { "type": "integer", "example": 1, "description": "from for meta." }, "to": { "type": "integer", "example": 1, "description": "to for meta." } }, "description": "Pagination, filter, or response metadata for this request." } }, "required": [ "success", "data", "meta" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **422**: Validation failed for search. The request was not applied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### POST /api/v1/smartlinks Operation: `createSmartlink` Create Smartlink Create a release smartlink with slug, title, release reference, and DSP destinations. Use the returned smartlink_id for analytics, preference, and sync calls. Security: ```json [ { "BearerAuth": [] } ] ``` #### Request body Request payload. Required. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "release_id": { "type": "string", "example": "b7a15d95-58f6-4f67-b5d1-89f4f5bfb4d8", "format": "uuid", "description": "Stable public release reference. Use this value in related endpoint paths and request bodies." }, "slug": { "type": "string", "example": "nova-vale-midnight-atlas", "description": "URL-safe slug used for public links or add-on references." }, "title": { "type": "string", "example": "Midnight Atlas", "description": "Catalog or content title shown in the dashboard and API responses." }, "destinations": { "type": "array", "items": { "type": "object", "additionalProperties": false, "properties": { "platform": { "type": "string", "example": "spotify", "description": "Streaming platform or destination key, such as spotify, apple_music, youtube_music, or deezer." }, "url": { "type": "string", "example": "https://open.spotify.com/album/4Gj9kL2mN8rT6bY1xQvP3z", "format": "uri", "description": "Public URL returned for this resource or action." }, "enabled": { "type": "boolean", "example": true, "description": "Whether this option or destination is currently enabled." } }, "required": [ "platform", "url" ] }, "description": "DSP and landing-page destination objects shown on the smartlink." } }, "required": [ "release_id", "slug", "title" ] } ``` #### Responses - **201**: Create Smartlink created the resource and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "Smartlink created.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." }, "data": { "type": "object", "additionalProperties": true, "properties": { "smartlink_id": { "type": "string", "example": "1fdf8564-81f7-4607-9c8b-154b62db8d5f", "format": "uuid", "description": "Stable public smartlink reference. Use this value in related endpoint paths and request bodies." }, "release": { "type": "object", "additionalProperties": true, "properties": { "release_id": { "type": "string", "example": "b7a15d95-58f6-4f67-b5d1-89f4f5bfb4d8", "format": "uuid", "description": "Stable public release reference. Use this value in related endpoint paths and request bodies." }, "title": { "type": "string", "example": "Midnight Atlas", "description": "Catalog or content title shown in the dashboard and API responses." }, "status": { "type": "string", "example": "draft", "description": "Current lifecycle status for this record." } }, "description": "Release summary or nested release object connected to this workflow." }, "slug": { "type": "string", "example": "nova-vale-midnight-atlas", "description": "URL-safe slug used for public links or add-on references." }, "title": { "type": "string", "example": "Midnight Atlas", "description": "Catalog or content title shown in the dashboard and API responses." }, "status": { "type": "string", "example": "published", "description": "Current lifecycle status for this record." }, "public_url": { "type": "string", "example": "https://links.northstar-distribution.co.uk/nova-vale-midnight-atlas", "format": "uri", "description": "Public URL returned for this resource or action." }, "destinations": { "type": "array", "items": { "type": "object", "additionalProperties": false, "properties": { "platform": { "type": "string", "example": "spotify", "description": "Streaming platform or destination key, such as spotify, apple_music, youtube_music, or deezer." }, "url": { "type": "string", "example": "https://open.spotify.com/album/4Gj9kL2mN8rT6bY1xQvP3z", "format": "uri", "description": "Public URL returned for this resource or action." }, "enabled": { "type": "boolean", "example": true, "description": "Whether this option or destination is currently enabled." } }, "required": [ "platform", "url" ] }, "description": "DSP and landing-page destination objects shown on the smartlink." }, "clicks": { "type": "integer", "example": 1840, "description": "Number of recorded smartlink clicks for the selected period or destination." }, "conversion_rate": { "type": "number", "example": 0.18, "description": "Percentage of visitors who clicked through or completed the measured smartlink action." }, "updated_at": { "type": "string", "example": "2026-07-04T10:15:00+00:00", "format": "date-time", "description": "Timestamp for when updated occurred, formatted as ISO 8601 when available." } }, "description": "Primary response payload for this request." } }, "required": [ "success", "message", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **422**: Validation failed for release_id. The request was not applied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### GET /api/v1/smartlinks/{smartlink_id} Operation: `getSmartlink` View Smartlink View Smartlink. Use it to create and maintain release landing pages, DSP destinations, analytics visibility, and personal or organization smartlink preferences. It returns public references and organization-visible fields only, so clients can safely use returned values in follow-up API calls. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `smartlink_id` in path (string, required): Public smartlink reference returned by the API. #### Responses - **200**: View Smartlink succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "data": { "type": "object", "additionalProperties": true, "properties": { "smartlink_id": { "type": "string", "example": "1fdf8564-81f7-4607-9c8b-154b62db8d5f", "format": "uuid", "description": "Stable public smartlink reference. Use this value in related endpoint paths and request bodies." }, "release": { "type": "object", "additionalProperties": true, "properties": { "release_id": { "type": "string", "example": "b7a15d95-58f6-4f67-b5d1-89f4f5bfb4d8", "format": "uuid", "description": "Stable public release reference. Use this value in related endpoint paths and request bodies." }, "title": { "type": "string", "example": "Midnight Atlas", "description": "Catalog or content title shown in the dashboard and API responses." }, "status": { "type": "string", "example": "draft", "description": "Current lifecycle status for this record." } }, "description": "Release summary or nested release object connected to this workflow." }, "slug": { "type": "string", "example": "nova-vale-midnight-atlas", "description": "URL-safe slug used for public links or add-on references." }, "title": { "type": "string", "example": "Midnight Atlas", "description": "Catalog or content title shown in the dashboard and API responses." }, "status": { "type": "string", "example": "published", "description": "Current lifecycle status for this record." }, "public_url": { "type": "string", "example": "https://links.northstar-distribution.co.uk/nova-vale-midnight-atlas", "format": "uri", "description": "Public URL returned for this resource or action." }, "destinations": { "type": "array", "items": { "type": "object", "additionalProperties": false, "properties": { "platform": { "type": "string", "example": "spotify", "description": "Streaming platform or destination key, such as spotify, apple_music, youtube_music, or deezer." }, "url": { "type": "string", "example": "https://open.spotify.com/album/4Gj9kL2mN8rT6bY1xQvP3z", "format": "uri", "description": "Public URL returned for this resource or action." }, "enabled": { "type": "boolean", "example": true, "description": "Whether this option or destination is currently enabled." } }, "required": [ "platform", "url" ] }, "description": "DSP and landing-page destination objects shown on the smartlink." }, "clicks": { "type": "integer", "example": 1840, "description": "Number of recorded smartlink clicks for the selected period or destination." }, "conversion_rate": { "type": "number", "example": 0.18, "description": "Percentage of visitors who clicked through or completed the measured smartlink action." }, "updated_at": { "type": "string", "example": "2026-07-04T10:15:00+00:00", "format": "date-time", "description": "Timestamp for when updated occurred, formatted as ISO 8601 when available." } }, "description": "Primary response payload for this request." } }, "required": [ "success", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **404**: Resource not found. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### PUT /api/v1/smartlinks/{smartlink_id} Operation: `updateSmartlink` Update Smartlink Replace editable smartlink fields such as title, destination list, or status by smartlink_id. Use this for full smartlink form saves. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `smartlink_id` in path (string, required): Public smartlink reference returned by the API. #### Request body Request payload. Required. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "title": { "type": "string", "example": "Midnight Atlas", "description": "Catalog or content title shown in the dashboard and API responses." }, "destinations": { "type": "array", "items": { "type": "object", "additionalProperties": false, "properties": { "platform": { "type": "string", "example": "spotify", "description": "Streaming platform or destination key, such as spotify, apple_music, youtube_music, or deezer." }, "url": { "type": "string", "example": "https://open.spotify.com/album/4Gj9kL2mN8rT6bY1xQvP3z", "format": "uri", "description": "Public URL returned for this resource or action." }, "enabled": { "type": "boolean", "example": true, "description": "Whether this option or destination is currently enabled." } }, "required": [ "platform", "url" ] }, "description": "DSP and landing-page destination objects shown on the smartlink." }, "status": { "type": "string", "example": "published", "description": "Current lifecycle status for this record." } }, "required": [ "title", "destinations" ] } ``` #### Responses - **200**: Update Smartlink succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "Smartlink updated.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." }, "data": { "type": "object", "additionalProperties": true, "properties": { "smartlink_id": { "type": "string", "example": "1fdf8564-81f7-4607-9c8b-154b62db8d5f", "format": "uuid", "description": "Stable public smartlink reference. Use this value in related endpoint paths and request bodies." }, "release": { "type": "object", "additionalProperties": true, "properties": { "release_id": { "type": "string", "example": "b7a15d95-58f6-4f67-b5d1-89f4f5bfb4d8", "format": "uuid", "description": "Stable public release reference. Use this value in related endpoint paths and request bodies." }, "title": { "type": "string", "example": "Midnight Atlas", "description": "Catalog or content title shown in the dashboard and API responses." }, "status": { "type": "string", "example": "draft", "description": "Current lifecycle status for this record." } }, "description": "Release summary or nested release object connected to this workflow." }, "slug": { "type": "string", "example": "nova-vale-midnight-atlas", "description": "URL-safe slug used for public links or add-on references." }, "title": { "type": "string", "example": "Midnight Atlas", "description": "Catalog or content title shown in the dashboard and API responses." }, "status": { "type": "string", "example": "published", "description": "Current lifecycle status for this record." }, "public_url": { "type": "string", "example": "https://links.northstar-distribution.co.uk/nova-vale-midnight-atlas", "format": "uri", "description": "Public URL returned for this resource or action." }, "destinations": { "type": "array", "items": { "type": "object", "additionalProperties": false, "properties": { "platform": { "type": "string", "example": "spotify", "description": "Streaming platform or destination key, such as spotify, apple_music, youtube_music, or deezer." }, "url": { "type": "string", "example": "https://open.spotify.com/album/4Gj9kL2mN8rT6bY1xQvP3z", "format": "uri", "description": "Public URL returned for this resource or action." }, "enabled": { "type": "boolean", "example": true, "description": "Whether this option or destination is currently enabled." } }, "required": [ "platform", "url" ] }, "description": "DSP and landing-page destination objects shown on the smartlink." }, "clicks": { "type": "integer", "example": 1840, "description": "Number of recorded smartlink clicks for the selected period or destination." }, "conversion_rate": { "type": "number", "example": 0.18, "description": "Percentage of visitors who clicked through or completed the measured smartlink action." }, "updated_at": { "type": "string", "example": "2026-07-04T10:15:00+00:00", "format": "date-time", "description": "Timestamp for when updated occurred, formatted as ISO 8601 when available." } }, "description": "Primary response payload for this request." } }, "required": [ "success", "message", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **404**: Resource not found. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **422**: Validation failed for destinations.0.url. The request was not applied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### PATCH /api/v1/smartlinks/{smartlink_id} Operation: `updateSmartlinkStatus` Update Smartlink Status Update a small subset of smartlink fields by smartlink_id, such as status changes, without resubmitting the full destination list. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `smartlink_id` in path (string, required): Public smartlink reference returned by the API. #### Request body Request payload. Required. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "status": { "type": "string", "example": "published", "description": "Current lifecycle status for this record." } }, "required": [ "status" ] } ``` #### Responses - **200**: Update Smartlink Status succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "Smartlink updated.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." }, "data": { "type": "object", "additionalProperties": true, "properties": { "smartlink_id": { "type": "string", "example": "1fdf8564-81f7-4607-9c8b-154b62db8d5f", "format": "uuid", "description": "Stable public smartlink reference. Use this value in related endpoint paths and request bodies." }, "release": { "type": "object", "additionalProperties": true, "properties": { "release_id": { "type": "string", "example": "b7a15d95-58f6-4f67-b5d1-89f4f5bfb4d8", "format": "uuid", "description": "Stable public release reference. Use this value in related endpoint paths and request bodies." }, "title": { "type": "string", "example": "Midnight Atlas", "description": "Catalog or content title shown in the dashboard and API responses." }, "status": { "type": "string", "example": "draft", "description": "Current lifecycle status for this record." } }, "description": "Release summary or nested release object connected to this workflow." }, "slug": { "type": "string", "example": "nova-vale-midnight-atlas", "description": "URL-safe slug used for public links or add-on references." }, "title": { "type": "string", "example": "Midnight Atlas", "description": "Catalog or content title shown in the dashboard and API responses." }, "status": { "type": "string", "example": "published", "description": "Current lifecycle status for this record." }, "public_url": { "type": "string", "example": "https://links.northstar-distribution.co.uk/nova-vale-midnight-atlas", "format": "uri", "description": "Public URL returned for this resource or action." }, "destinations": { "type": "array", "items": { "type": "object", "additionalProperties": false, "properties": { "platform": { "type": "string", "example": "spotify", "description": "Streaming platform or destination key, such as spotify, apple_music, youtube_music, or deezer." }, "url": { "type": "string", "example": "https://open.spotify.com/album/4Gj9kL2mN8rT6bY1xQvP3z", "format": "uri", "description": "Public URL returned for this resource or action." }, "enabled": { "type": "boolean", "example": true, "description": "Whether this option or destination is currently enabled." } }, "required": [ "platform", "url" ] }, "description": "DSP and landing-page destination objects shown on the smartlink." }, "clicks": { "type": "integer", "example": 1840, "description": "Number of recorded smartlink clicks for the selected period or destination." }, "conversion_rate": { "type": "number", "example": 0.18, "description": "Percentage of visitors who clicked through or completed the measured smartlink action." }, "updated_at": { "type": "string", "example": "2026-07-04T10:15:00+00:00", "format": "date-time", "description": "Timestamp for when updated occurred, formatted as ISO 8601 when available." } }, "description": "Primary response payload for this request." } }, "required": [ "success", "message", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **404**: Resource not found. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **422**: Validation failed for status. The request was not applied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### DELETE /api/v1/smartlinks/{smartlink_id} Operation: `deleteSmartlink` Delete Smartlink Delete Smartlink. Use it to create and maintain release landing pages, DSP destinations, analytics visibility, and personal or organization smartlink preferences. It removes, revokes, or cancels the target when permissions and resource state allow it, then returns a confirmation or policy error. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `smartlink_id` in path (string, required): Public smartlink reference returned by the API. #### Responses - **200**: Delete Smartlink succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "Smartlink deleted.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." } }, "required": [ "success", "message" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **404**: Resource not found. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### GET /api/v1/smartlinks/{smartlink_id}/analytics Operation: `getSmartlinkAnalytics` View Smartlink Analytics Return analytics for a smartlink by smartlink_id, including organization-visible engagement metrics for release landing page performance. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `smartlink_id` in path (string, required): Public smartlink reference returned by the API. #### Responses - **200**: View Smartlink Analytics succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "data": { "type": "object", "additionalProperties": true, "properties": { "smartlink_id": { "type": "string", "example": "1fdf8564-81f7-4607-9c8b-154b62db8d5f", "format": "uuid", "description": "Stable public smartlink reference. Use this value in related endpoint paths and request bodies." }, "clicks": { "type": "integer", "example": 1840, "description": "Number of recorded smartlink clicks for the selected period or destination." }, "top_destinations": { "type": "array", "items": { "type": "object", "additionalProperties": true, "properties": { "platform": { "type": "string", "example": "spotify", "description": "platform for top_destinations." }, "clicks": { "type": "integer", "example": 970, "description": "clicks for top_destinations." } } }, "description": "Highest-performing smartlink destinations for the selected analytics period." }, "countries": { "type": "array", "items": { "type": "object", "additionalProperties": true, "properties": { "code": { "type": "string", "example": "GB", "description": "code for countries." }, "clicks": { "type": "integer", "example": 620, "description": "clicks for countries." } } }, "description": "Country options available for profile, release, rights, and billing forms." } }, "description": "Primary response payload for this request." } }, "required": [ "success", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **404**: Resource not found. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### GET /api/v1/smartlinks/{smartlink_id}/preferences Operation: `getSmartlinkPreferences` View Smartlink Preferences View Smartlink Preferences. Use it to create and maintain release landing pages, DSP destinations, analytics visibility, and personal or organization smartlink preferences. It returns public references and organization-visible fields only, so clients can safely use returned values in follow-up API calls. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `smartlink_id` in path (string, required): Public smartlink reference returned by the API. #### Responses - **200**: View Smartlink Preferences succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "data": { "type": "object", "additionalProperties": true, "properties": { "smartlink_id": { "type": "string", "example": "1fdf8564-81f7-4607-9c8b-154b62db8d5f", "format": "uuid", "description": "Stable public smartlink reference. Use this value in related endpoint paths and request bodies." }, "user_preferences": { "type": "object", "additionalProperties": true, "properties": { "default_destination": { "type": "string", "example": "spotify", "description": "Preferred DSP destination for the authenticated user when opening or managing this smartlink." } }, "description": "Smartlink preferences stored for the authenticated user." }, "organization_preferences": { "type": "object", "additionalProperties": true, "properties": { "show_branding": { "type": "boolean", "example": true, "description": "Whether organization branding should be displayed on the smartlink page." }, "collect_analytics": { "type": "boolean", "example": true, "description": "Whether engagement analytics should be collected for the smartlink when supported by account settings." } }, "description": "Smartlink preferences applied across the organization." } }, "description": "Primary response payload for this request." } }, "required": [ "success", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **404**: Resource not found. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### PUT /api/v1/smartlinks/{smartlink_id}/preferences/me Operation: `updateMySmartlinkPreferences` Update My Smartlink Preferences Update personal defaults for how the authenticated user works with a smartlink, such as default destination preference, without changing organization-wide smartlink settings. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `smartlink_id` in path (string, required): Public smartlink reference returned by the API. #### Request body Request payload. Required. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "default_destination": { "type": "string", "example": "spotify", "description": "Preferred DSP destination for the authenticated user when opening or managing this smartlink." } }, "required": [ "default_destination" ] } ``` #### Responses - **200**: Update My Smartlink Preferences succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "Smartlink preferences updated.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." } }, "required": [ "success", "message" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **404**: Resource not found. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **422**: Validation failed for default_destination. The request was not applied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### PUT /api/v1/smartlinks/{smartlink_id}/preferences/org Operation: `updateOrganizationSmartlinkPreferences` Update Organization Smartlink Preferences Update organization-wide smartlink preferences by smartlink_id, such as branding visibility and analytics collection settings. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `smartlink_id` in path (string, required): Public smartlink reference returned by the API. #### Request body Request payload. Required. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "show_branding": { "type": "boolean", "example": true, "description": "Whether organization branding should be displayed on the smartlink page." }, "collect_analytics": { "type": "boolean", "example": true, "description": "Whether engagement analytics should be collected for the smartlink when supported by account settings." } }, "required": [ "show_branding", "collect_analytics" ] } ``` #### Responses - **200**: Update Organization Smartlink Preferences succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "Organization smartlink preferences updated.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." } }, "required": [ "success", "message" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **404**: Resource not found. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **422**: Validation failed for show_branding. The request was not applied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### POST /api/v1/smartlinks/{smartlink_id}/sync Operation: `syncSmartlink` Sync Smartlink Refresh a smartlink by smartlink_id so destination and release data reflect the latest catalog state visible to the organization. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `smartlink_id` in path (string, required): Public smartlink reference returned by the API. #### Responses - **200**: Sync Smartlink succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "Smartlink synced.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." }, "data": { "type": "object", "additionalProperties": true, "properties": { "smartlink_id": { "type": "string", "example": "1fdf8564-81f7-4607-9c8b-154b62db8d5f", "format": "uuid", "description": "Stable public smartlink reference. Use this value in related endpoint paths and request bodies." }, "release": { "type": "object", "additionalProperties": true, "properties": { "release_id": { "type": "string", "example": "b7a15d95-58f6-4f67-b5d1-89f4f5bfb4d8", "format": "uuid", "description": "Stable public release reference. Use this value in related endpoint paths and request bodies." }, "title": { "type": "string", "example": "Midnight Atlas", "description": "Catalog or content title shown in the dashboard and API responses." }, "status": { "type": "string", "example": "draft", "description": "Current lifecycle status for this record." } }, "description": "Release summary or nested release object connected to this workflow." }, "slug": { "type": "string", "example": "nova-vale-midnight-atlas", "description": "URL-safe slug used for public links or add-on references." }, "title": { "type": "string", "example": "Midnight Atlas", "description": "Catalog or content title shown in the dashboard and API responses." }, "status": { "type": "string", "example": "published", "description": "Current lifecycle status for this record." }, "public_url": { "type": "string", "example": "https://links.northstar-distribution.co.uk/nova-vale-midnight-atlas", "format": "uri", "description": "Public URL returned for this resource or action." }, "destinations": { "type": "array", "items": { "type": "object", "additionalProperties": false, "properties": { "platform": { "type": "string", "example": "spotify", "description": "Streaming platform or destination key, such as spotify, apple_music, youtube_music, or deezer." }, "url": { "type": "string", "example": "https://open.spotify.com/album/4Gj9kL2mN8rT6bY1xQvP3z", "format": "uri", "description": "Public URL returned for this resource or action." }, "enabled": { "type": "boolean", "example": true, "description": "Whether this option or destination is currently enabled." } }, "required": [ "platform", "url" ] }, "description": "DSP and landing-page destination objects shown on the smartlink." }, "clicks": { "type": "integer", "example": 1840, "description": "Number of recorded smartlink clicks for the selected period or destination." }, "conversion_rate": { "type": "number", "example": 0.18, "description": "Percentage of visitors who clicked through or completed the measured smartlink action." }, "updated_at": { "type": "string", "example": "2026-07-04T10:15:00+00:00", "format": "date-time", "description": "Timestamp for when updated occurred, formatted as ISO 8601 when available." } }, "description": "Primary response payload for this request." } }, "required": [ "success", "message", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **404**: Resource not found. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ## Theme Editor Read, save, and publish organization theme profiles for supported whitelabel surfaces. ### POST /api/v1/theme-editor/draft Operation: `saveThemeDraft` Save Theme Draft Save Theme Draft. Use it to save, inspect, and publish organization visual branding drafts for the account experience. It applies the requested change and returns the updated resource, validation result, or action status needed for the next API step. Security: ```json [ { "BearerAuth": [] } ] ``` #### Request body Request payload. Required. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "primary_color": { "type": "string", "example": "#111827", "description": "Primary brand color as a hex value used for prominent buttons, links, and branded surfaces." }, "accent_color": { "type": "string", "example": "#2DD4BF", "description": "Secondary brand color as a hex value used for highlights and supporting UI elements." }, "logo_url": { "type": "string", "example": "https://assets.spacemedia-docs.invalid/brands/northstar-records/logo.svg", "format": "uri", "description": "Public URL returned for this resource or action." }, "site_title": { "type": "string", "example": "Northstar Distribution Portal", "description": "Organization display title shown in branded account surfaces." } }, "required": [ "primary_color", "accent_color", "site_title" ] } ``` #### Responses - **200**: Save Theme Draft succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "Theme draft saved.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." }, "data": { "type": "object", "additionalProperties": true, "properties": { "brand_name": { "type": "string", "example": "Northstar Distribution", "description": "Organization brand name shown on customer-facing pages and branded account surfaces." }, "site_title": { "type": "string", "example": "Northstar Distribution Portal", "description": "Organization display title shown in branded account surfaces." }, "logo_url": { "type": "string", "example": "https://assets.spacemedia-docs.invalid/brands/northstar-records/logo.svg", "format": "uri", "description": "Public URL returned for this resource or action." }, "primary_color": { "type": "string", "example": "#111827", "description": "Primary brand color as a hex value used for prominent buttons, links, and branded surfaces." }, "accent_color": { "type": "string", "example": "#2DD4BF", "description": "Secondary brand color as a hex value used for highlights and supporting UI elements." }, "mode": { "type": "string", "example": "draft", "description": "Mode used by the workflow, such as hosted checkout, embedded checkout, draft, preview, or published state." }, "last_published_at": { "type": "string", "example": "2026-06-28T16:10:00+00:00", "format": "date-time", "description": "Timestamp for when last published occurred, formatted as ISO 8601 when available." } }, "description": "Primary response payload for this request." } }, "required": [ "success", "message", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **422**: Validation failed for primary_color. The request was not applied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### GET /api/v1/theme-editor/profile Operation: `getThemeEditorProfile` View Theme Profile View Theme Profile. Use it to save, inspect, and publish organization visual branding drafts for the account experience. It returns public references and organization-visible fields only, so clients can safely use returned values in follow-up API calls. Security: ```json [ { "BearerAuth": [] } ] ``` #### Responses - **200**: View Theme Profile succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "data": { "type": "object", "additionalProperties": true, "properties": { "brand_name": { "type": "string", "example": "Northstar Distribution", "description": "Organization brand name shown on customer-facing pages and branded account surfaces." }, "site_title": { "type": "string", "example": "Northstar Distribution Portal", "description": "Organization display title shown in branded account surfaces." }, "logo_url": { "type": "string", "example": "https://assets.spacemedia-docs.invalid/brands/northstar-records/logo.svg", "format": "uri", "description": "Public URL returned for this resource or action." }, "primary_color": { "type": "string", "example": "#111827", "description": "Primary brand color as a hex value used for prominent buttons, links, and branded surfaces." }, "accent_color": { "type": "string", "example": "#2DD4BF", "description": "Secondary brand color as a hex value used for highlights and supporting UI elements." }, "mode": { "type": "string", "example": "draft", "description": "Mode used by the workflow, such as hosted checkout, embedded checkout, draft, preview, or published state." }, "last_published_at": { "type": "string", "example": "2026-06-28T16:10:00+00:00", "format": "date-time", "description": "Timestamp for when last published occurred, formatted as ISO 8601 when available." } }, "description": "Primary response payload for this request." } }, "required": [ "success", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### POST /api/v1/theme-editor/publish Operation: `publishThemeProfile` Publish Theme Profile Publish Theme Profile. Use it to save, inspect, and publish organization visual branding drafts for the account experience. It applies the requested change and returns the updated resource, validation result, or action status needed for the next API step. Security: ```json [ { "BearerAuth": [] } ] ``` #### Responses - **200**: Publish Theme Profile succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "Theme profile published.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." }, "data": { "type": "object", "additionalProperties": true, "properties": { "brand_name": { "type": "string", "example": "Northstar Distribution", "description": "Organization brand name shown on customer-facing pages and branded account surfaces." }, "site_title": { "type": "string", "example": "Northstar Distribution Portal", "description": "Organization display title shown in branded account surfaces." }, "logo_url": { "type": "string", "example": "https://assets.spacemedia-docs.invalid/brands/northstar-records/logo.svg", "format": "uri", "description": "Public URL returned for this resource or action." }, "primary_color": { "type": "string", "example": "#111827", "description": "Primary brand color as a hex value used for prominent buttons, links, and branded surfaces." }, "accent_color": { "type": "string", "example": "#2DD4BF", "description": "Secondary brand color as a hex value used for highlights and supporting UI elements." }, "mode": { "type": "string", "example": "published", "description": "Mode used by the workflow, such as hosted checkout, embedded checkout, draft, preview, or published state." }, "last_published_at": { "type": "string", "example": "2026-07-04T10:15:00+00:00", "format": "date-time", "description": "Timestamp for when last published occurred, formatted as ISO 8601 when available." } }, "description": "Primary response payload for this request." } }, "required": [ "success", "message", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ## Email Theme Preview, save, read, and publish branded transactional-email theme settings. ### POST /api/v1/email-theme/draft Operation: `saveEmailThemeDraft` Save Email Theme Draft Save Email Theme Draft. Use it to save, preview, and publish branded transactional email settings for the organization. It applies the requested change and returns the updated resource, validation result, or action status needed for the next API step. Security: ```json [ { "BearerAuth": [] } ] ``` #### Request body Request payload. Required. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "sender_name": { "type": "string", "example": "Northstar Distribution", "description": "Display name shown as the sender on branded transactional email previews and published email settings." }, "sender_email": { "type": "string", "example": "support@northstar-distribution.co.uk", "description": "Reply-capable sender email address used for branded transactional email previews and published email settings." }, "primary_color": { "type": "string", "example": "#111827", "description": "Primary brand color as a hex value used for prominent buttons, links, and branded surfaces." }, "footer_text": { "type": "string", "example": "Northstar Distribution, London", "description": "Short footer text shown in branded transactional emails, usually support or legal copy for the organization." } }, "required": [ "sender_name", "sender_email", "primary_color" ] } ``` #### Responses - **200**: Save Email Theme Draft succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "Email theme draft saved.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." }, "data": { "type": "object", "additionalProperties": true, "properties": { "sender_name": { "type": "string", "example": "Northstar Distribution", "description": "Display name shown as the sender on branded transactional email previews and published email settings." }, "sender_email": { "type": "string", "example": "support@northstar-distribution.co.uk", "description": "Reply-capable sender email address used for branded transactional email previews and published email settings." }, "primary_color": { "type": "string", "example": "#111827", "description": "Primary brand color as a hex value used for prominent buttons, links, and branded surfaces." }, "footer_text": { "type": "string", "example": "Northstar Distribution, London", "description": "Short footer text shown in branded transactional emails, usually support or legal copy for the organization." }, "mode": { "type": "string", "example": "draft", "description": "Mode used by the workflow, such as hosted checkout, embedded checkout, draft, preview, or published state." }, "last_published_at": { "type": "string", "example": "2026-06-28T16:10:00+00:00", "format": "date-time", "description": "Timestamp for when last published occurred, formatted as ISO 8601 when available." } }, "description": "Primary response payload for this request." } }, "required": [ "success", "message", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **422**: Validation failed for sender_name. The request was not applied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### POST /api/v1/email-theme/preview Operation: `previewEmailTheme` Preview Email Theme Preview Email Theme. Use it to save, preview, and publish branded transactional email settings for the organization. It applies the requested change and returns the updated resource, validation result, or action status needed for the next API step. Security: ```json [ { "BearerAuth": [] } ] ``` #### Request body Request payload. Required. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "template": { "type": "string", "example": "release_submitted", "description": "Email template key to preview, such as an invitation, release notification, or billing message supported by the account." }, "recipient_email": { "type": "string", "example": "ops@northstar-distribution.co.uk", "description": "Email address that should receive the preview message." } }, "required": [ "template", "recipient_email" ] } ``` #### Responses - **200**: Preview Email Theme succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "data": { "type": "object", "additionalProperties": true, "properties": { "preview_html": { "type": "string", "example": "

Midnight Atlas submitted

", "description": "Rendered email preview HTML for the requested template and draft settings." } }, "description": "Primary response payload for this request." } }, "required": [ "success", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **422**: Validation failed for template. The request was not applied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### GET /api/v1/email-theme/profile Operation: `getEmailThemeProfile` View Email Theme Profile View Email Theme Profile. Use it to save, preview, and publish branded transactional email settings for the organization. It returns public references and organization-visible fields only, so clients can safely use returned values in follow-up API calls. Security: ```json [ { "BearerAuth": [] } ] ``` #### Responses - **200**: View Email Theme Profile succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "data": { "type": "object", "additionalProperties": true, "properties": { "sender_name": { "type": "string", "example": "Northstar Distribution", "description": "Display name shown as the sender on branded transactional email previews and published email settings." }, "sender_email": { "type": "string", "example": "support@northstar-distribution.co.uk", "description": "Reply-capable sender email address used for branded transactional email previews and published email settings." }, "primary_color": { "type": "string", "example": "#111827", "description": "Primary brand color as a hex value used for prominent buttons, links, and branded surfaces." }, "footer_text": { "type": "string", "example": "Northstar Distribution, London", "description": "Short footer text shown in branded transactional emails, usually support or legal copy for the organization." }, "mode": { "type": "string", "example": "draft", "description": "Mode used by the workflow, such as hosted checkout, embedded checkout, draft, preview, or published state." }, "last_published_at": { "type": "string", "example": "2026-06-28T16:10:00+00:00", "format": "date-time", "description": "Timestamp for when last published occurred, formatted as ISO 8601 when available." } }, "description": "Primary response payload for this request." } }, "required": [ "success", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ### POST /api/v1/email-theme/publish Operation: `publishEmailTheme` Publish Email Theme Publish Email Theme. Use it to save, preview, and publish branded transactional email settings for the organization. It applies the requested change and returns the updated resource, validation result, or action status needed for the next API step. Security: ```json [ { "BearerAuth": [] } ] ``` #### Responses - **200**: Publish Email Theme succeeded and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "Email theme published.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." }, "data": { "type": "object", "additionalProperties": true, "properties": { "sender_name": { "type": "string", "example": "Northstar Distribution", "description": "Display name shown as the sender on branded transactional email previews and published email settings." }, "sender_email": { "type": "string", "example": "support@northstar-distribution.co.uk", "description": "Reply-capable sender email address used for branded transactional email previews and published email settings." }, "primary_color": { "type": "string", "example": "#111827", "description": "Primary brand color as a hex value used for prominent buttons, links, and branded surfaces." }, "footer_text": { "type": "string", "example": "Northstar Distribution, London", "description": "Short footer text shown in branded transactional emails, usually support or legal copy for the organization." }, "mode": { "type": "string", "example": "published", "description": "Mode used by the workflow, such as hosted checkout, embedded checkout, draft, preview, or published state." }, "last_published_at": { "type": "string", "example": "2026-07-04T10:15:00+00:00", "format": "date-time", "description": "Timestamp for when last published occurred, formatted as ISO 8601 when available." } }, "description": "Primary response payload for this request." } }, "required": [ "success", "message", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ## Feedback Submit organization-visible product and integration feedback with safe diagnostic context. ### POST /api/v1/platform-feedback Operation: `submitPlatformFeedback` Submit Platform Feedback Submit feedback about an API, catalog, billing, or account workflow. Include the page_url when feedback came from a visible user interface. Security: ```json [ { "BearerAuth": [] } ] ``` #### Request body Request payload. Required. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "category": { "type": "string", "example": "api_docs", "description": "Feedback category that helps route the message, such as catalog, billing, API, account, or support." }, "subject": { "type": "string", "example": "Need callback example for release submission", "description": "Short feedback subject that summarizes the issue or product request." }, "message": { "type": "string", "example": "Please add a callback guide for release status changes.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." }, "page_url": { "type": "string", "example": "https://docs.spacemedia.uk/delivery-api/introduction", "format": "uri", "description": "Public URL returned for this resource or action." } }, "required": [ "category", "subject", "message" ] } ``` #### Responses - **201**: Submit Platform Feedback created the resource and returns the documented response body. **application/json** ```json { "type": "object", "additionalProperties": true, "properties": { "success": { "type": "boolean", "example": true, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "Feedback submitted.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." }, "data": { "type": "object", "additionalProperties": true, "properties": { "feedback_id": { "type": "string", "example": "3ad65f11-6982-4f42-86e7-08976cb55114", "format": "uuid", "description": "Stable public feedback reference. Use this value in related endpoint paths and request bodies." }, "status": { "type": "string", "example": "received", "description": "Current lifecycle status for this record." } }, "description": "Primary response payload for this request." } }, "required": [ "success", "message", "data" ] } ``` - **401**: Authentication failed. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **403**: Permission denied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **422**: Validation failed for category. The request was not applied. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **429**: Rate limit reached. Retry after the client has slowed down. **application/json** ```json { "$ref": "#/components/schemas/ApiError" } ``` - **500**: Response ## DDEX Configure approved partner connections and manage ERN validation, export, delivery, import, claim, acknowledgement, retry, and conformance workflows. ### GET /api/v1/ddex/standards Operation: `getDdexStandards` Get DDEX compatibility matrix Read the exact ERN, Release Profile, AVS, choreography, feature, migration, schema-asset, and staging simulation policy supported by the Enterprise Delivery API. Security: ```json [ { "BearerAuth": [] } ] ``` #### Responses - **200**: Response - **401**: Response - **403**: Response - **429**: Response - **500**: Response ### GET /api/v1/ddex/sender-identities Operation: `listDdexSenderIdentities` List DDEX sender identities List tenant-owned DPID sender identities and their attestation state before configuring a versioned partner connection. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - Reference: `#/components/parameters/Page` - Reference: `#/components/parameters/PageSize` #### Responses - **200**: Response - **401**: Response - **403**: Response - **429**: Response - **500**: Response ### POST /api/v1/ddex/sender-identities Operation: `createDdexSenderIdentity` Create DDEX sender identity Attest and register an organization DPID sender identity for later use by sandbox or approved live partner connections. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - Reference: `#/components/parameters/IdempotencyKey` #### Request body Required. **application/json** ```json { "type": "object", "required": [ "name", "dpid", "attestation" ], "properties": { "name": { "type": "string", "minLength": 1, "maxLength": 150 }, "dpid": { "type": "string", "maxLength": 100, "description": "Valid PADPIDA identifier in canonical or human-readable hyphenated form." }, "attestation": { "type": "boolean", "const": true, "description": "Must be true to attest that the organization controls this DPID." } } } ``` #### Responses - **201**: Response - **401**: Response - **403**: Response - **422**: Response - **429**: Response - **500**: Response ### GET /api/v1/ddex/connections Operation: `listDdexConnections` List DDEX partner connections List versioned partner capability profiles, commercial routes, exact standards, environments, and current health without returning secrets. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - Reference: `#/components/parameters/Page` - Reference: `#/components/parameters/PageSize` #### Responses - **200**: Response - **401**: Response - **403**: Response - **429**: Response - **500**: Response ### POST /api/v1/ddex/connections Operation: `createDdexConnection` Create DDEX partner connection Create a locked draft connection that pins commercial route, DPIDs, ERN, profile, AVS, choreography, ownership, and partner contract rules. Creation never enables transport. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - Reference: `#/components/parameters/IdempotencyKey` #### Request body Required. **application/json** ```json { "type": "object", "additionalProperties": false, "required": [ "name", "partner_name", "integration_owner_reference", "commercial_route", "direction", "environment", "remote_dpid", "ern_version", "release_profile", "avs_version", "choreography", "hosting_mode", "auth_type" ], "properties": { "name": { "type": "string", "minLength": 1, "maxLength": 150 }, "partner_name": { "type": "string", "minLength": 1, "maxLength": 150 }, "sender_identity_reference": { "type": "string", "format": "uuid", "description": "Required for direct_partner. Omit for spacemedia_delivery_deal, which always uses the SpaceMedia platform DPID." }, "integration_owner_reference": { "type": "string", "format": "uuid" }, "commercial_route": { "type": "string", "enum": [ "spacemedia_delivery_deal", "direct_partner" ] }, "direction": { "type": "string", "enum": [ "outbound", "inbound", "bidirectional" ] }, "environment": { "type": "string", "enum": [ "sandbox", "live" ] }, "remote_dpid": { "type": "string", "minLength": 1, "maxLength": 100, "description": "Partner DPID in canonical no-hyphen form or human-readable hyphenated form. XML always uses the canonical no-hyphen form." }, "ern_version": { "type": "string", "enum": [ "4.3.0", "4.3.1", "4.3.2" ] }, "release_profile": { "type": "string", "enum": [ "Audio", "SimpleAudioSingle" ] }, "avs_version": { "type": "string", "enum": [ "011" ] }, "choreography": { "type": "string", "enum": [ "web_service_1_8", "cloud_storage_1_8_1" ] }, "hosting_mode": { "type": "string", "enum": [ "spacemedia_managed", "partner_managed" ] }, "auth_type": { "type": "string", "enum": [ "basic", "bearer", "sftp_password", "sftp_key" ] }, "endpoint_url": { "type": [ "string", "null" ], "format": "uri", "maxLength": 2048 }, "agreement_reference": { "type": [ "string", "null" ], "maxLength": 191 }, "supersedes_reference": { "type": [ "string", "null" ], "format": "uuid" }, "capabilities": { "type": [ "array", "null" ], "items": { "type": "string" }, "uniqueItems": true }, "contract_rules": { "type": [ "object", "null" ], "additionalProperties": true }, "credentials": { "type": [ "object", "null" ], "additionalProperties": true, "writeOnly": true, "description": "Partner credentials accepted for storage but never returned by the API." } } } ``` #### Responses - **201**: Versioned DDEX partner connection created without returning stored credentials. **application/json** ```json { "$ref": "#/components/schemas/DdexConnectionResult" } ``` - **401**: Response - **403**: Response - **422**: Response - **429**: Response - **500**: Response ### POST /api/v1/ddex/connections/{reference}/activation-request Operation: `requestDdexConnectionActivation` Request DDEX connection activation Submit a locked draft connection for SpaceMedia connection activation review and sandbox conformance testing. This is operational connection review, not SpaceMedia release review. No partner certificate is required. Transport remains disabled until review, conformance, health, platform, contract, and environment gates pass. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `reference` in path (string, required) - Reference: `#/components/parameters/IdempotencyKey` #### Responses - **202**: Response - **401**: Response - **403**: Response - **404**: Response - **409**: Response - **422**: Response - **429**: Response - **500**: Response ### POST /api/v1/ddex/connections/{reference}/rotate-secret Operation: `updateDdexConnectionSecret` Rotate DDEX connection secret Replace encrypted partner credentials without returning the stored values and require a new health check before operational use. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `reference` in path (string, required) - Reference: `#/components/parameters/IdempotencyKey` #### Request body Required. **application/json** ```json { "type": "object", "required": [ "credentials" ], "properties": { "credentials": { "type": "object", "additionalProperties": true } } } ``` #### Responses - **200**: DDEX partner credentials replaced without returning the stored values. **application/json** ```json { "$ref": "#/components/schemas/DdexConnectionResult" } ``` - **401**: Response - **403**: Response - **404**: Response - **422**: Response - **429**: Response - **500**: Response ### POST /api/v1/ddex/connections/{reference}/health-check Operation: `startDdexConnectionHealthCheck` Start DDEX connection health check Check credentials, endpoint configuration, licensed schema assets, live transport gates, and connection readiness without exposing secrets. Staging sandbox checks are isolated and report whether simulation or an external probe was used. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `reference` in path (string, required) - Reference: `#/components/parameters/IdempotencyKey` #### Responses - **202**: Response - **401**: Response - **403**: Response - **404**: Response - **429**: Response - **500**: Response ### GET /api/v1/ddex/connections/{reference}/feed Operation: `getDdexWebServiceFeed` Get DDEX Web Service feed Read the authenticated Atom feed of current available messages for a Web Service 1.8 sender connection and follow payload links. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `reference` in path (string, required) #### Responses - **200**: The current authenticated Atom feed was returned with at most one current message per release. **application/atom+xml** ```json { "type": "string" } ``` - **401**: Response - **403**: Response - **404**: Response - **422**: Response - **429**: Response - **500**: Response ### GET /api/v1/ddex/deal-profiles Operation: `listDdexDealProfiles` List DDEX deal profiles List explicit commercial models, use types, territories, validity windows, and partner terms available to DDEX operations. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - Reference: `#/components/parameters/Page` - Reference: `#/components/parameters/PageSize` #### Responses - **200**: Response - **401**: Response - **403**: Response - **429**: Response - **500**: Response ### POST /api/v1/ddex/deal-profiles Operation: `createDdexDealProfile` Create DDEX deal profile Create a reusable deal profile with explicit use types, territories, validity periods, commercial model, and contract terms. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - Reference: `#/components/parameters/IdempotencyKey` #### Request body Required. **application/json** ```json { "type": "object", "additionalProperties": false, "required": [ "name", "commercial_model", "use_types", "territories" ], "properties": { "name": { "type": "string", "minLength": 1, "maxLength": 150 }, "commercial_model": { "type": "string", "minLength": 1, "maxLength": 100 }, "use_types": { "type": "array", "minItems": 1, "items": { "type": "string", "maxLength": 100 } }, "territories": { "type": "array", "minItems": 1, "items": { "type": "string", "maxLength": 3 } }, "valid_from": { "type": [ "string", "null" ], "description": "ISO 8601 date or date-time when the deal becomes valid." }, "valid_until": { "type": [ "string", "null" ], "description": "ISO 8601 date or date-time after valid_from when the deal ends." }, "terms": { "type": [ "object", "null" ], "additionalProperties": true } } } ``` #### Responses - **201**: Response - **401**: Response - **403**: Response - **422**: Response - **429**: Response - **500**: Response ### POST /api/v1/ddex/uploads Operation: `uploadNativeDdexMessage` Upload native DDEX message Accept a native ERN message for secure parsing and immutable preservation before validation, relay, export, or create-only import. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - Reference: `#/components/parameters/IdempotencyKey` #### Request body Required. **application/json** ```json { "$ref": "#/components/schemas/DdexOperationInput" } ``` #### Responses - **202**: Response - **401**: Response - **403**: Response - **422**: Response - **429**: Response - **500**: Response ### POST /api/v1/ddex/validations Operation: `validateDdexOperation` Validate DDEX operation Run secure XML, DDEX, catalog, contract, transport, review, and state checks without transmitting the resulting package. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - Reference: `#/components/parameters/IdempotencyKey` #### Request body Required. **application/json** ```json { "$ref": "#/components/schemas/DdexOperationInput" } ``` #### Responses - **202**: Response - **401**: Response - **403**: Response - **422**: Response - **429**: Response - **500**: Response ### POST /api/v1/ddex/exports Operation: `createDdexExport` Create DDEX export Snapshot a SpaceMedia release or preserve native ERN XML, validate it, and create a downloadable immutable package without transmission. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - Reference: `#/components/parameters/IdempotencyKey` #### Request body Required. **application/json** ```json { "$ref": "#/components/schemas/DdexOperationInput" } ``` #### Responses - **202**: Response - **401**: Response - **403**: Response - **422**: Response - **429**: Response - **500**: Response ### POST /api/v1/ddex/deliveries Operation: `createDdexDelivery` Create DDEX delivery Validate, package, and queue delivery for a release or native ERN. SpaceMedia delivery deals wait for SpaceMedia review; direct partners do not. Staging sandbox transport is simulated and never contacts a partner endpoint. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - Reference: `#/components/parameters/IdempotencyKey` #### Request body Required. **application/json** ```json { "$ref": "#/components/schemas/DdexOperationInput" } ``` #### Responses - **202**: Response - **401**: Response - **403**: Response - **422**: Response - **429**: Response - **500**: Response ### GET /api/v1/ddex/batches Operation: `listDdexBatches` List DDEX delivery batches List Cloud Storage 1.8.1 batches, message counts, completion state, and immutable manifest checksum for the organization. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - Reference: `#/components/parameters/Page` - Reference: `#/components/parameters/PageSize` #### Responses - **200**: Response - **401**: Response - **403**: Response - **429**: Response - **500**: Response ### POST /api/v1/ddex/batches Operation: `createDdexBatch` Create DDEX delivery batch Group eligible messages for one Cloud Storage 1.8.1 connection and publish an immutable batch manifest after all message artifacts. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - Reference: `#/components/parameters/IdempotencyKey` #### Request body Required. **application/json** ```json { "type": "object", "required": [ "connection_reference", "message_references" ], "properties": { "connection_reference": { "type": "string", "format": "uuid" }, "message_references": { "type": "array", "minItems": 1, "maxItems": 1000, "uniqueItems": true, "items": { "type": "string", "format": "uuid" } } } } ``` #### Responses - **202**: Response - **401**: Response - **403**: Response - **409**: Response - **422**: Response - **429**: Response - **500**: Response ### GET /api/v1/ddex/imports Operation: `listDdexImports` List native DDEX imports List atomic create-only inbound import requests, preserved source messages, unmapped fields, and resulting draft release references. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - Reference: `#/components/parameters/Page` - Reference: `#/components/parameters/PageSize` #### Responses - **200**: Response - **401**: Response - **403**: Response - **429**: Response - **500**: Response ### POST /api/v1/ddex/imports Operation: `createDdexImport` Create native DDEX import Validate a native inbound ERN under an inbound connection and stage an atomic create-only draft import owned by the configured integration user. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - Reference: `#/components/parameters/IdempotencyKey` #### Request body Required. **application/json** ```json { "type": "object", "additionalProperties": false, "required": [ "connection_reference", "native_xml", "action" ], "properties": { "connection_reference": { "type": "string", "format": "uuid" }, "native_xml": { "type": "string", "maxLength": 26214400, "description": "Secure, well-formed native ERN XML up to 25 MiB." }, "action": { "type": "string", "enum": [ "insert" ] }, "metadata_overlay": { "type": [ "object", "null" ], "additionalProperties": true } } } ``` #### Responses - **202**: Response - **401**: Response - **403**: Response - **422**: Response - **429**: Response - **500**: Response ### GET /api/v1/ddex/imports/{reference} Operation: `getDdexImport` Get native DDEX import Get the canonical status, preserved source-message reference, unmapped fields, and created draft release references for one atomic inbound import. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `reference` in path (string, required) #### Responses - **200**: Response - **401**: Response - **403**: Response - **404**: Response - **429**: Response - **500**: Response ### GET /api/v1/ddex/messages Operation: `listDdexMessages` List DDEX message operations List immutable message operations and their separate control, SpaceMedia review, transport, partner, and webhook delivery states. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - Reference: `#/components/parameters/Page` - Reference: `#/components/parameters/PageSize` - `status` in query (string): Return only messages in the exact control-plane status. #### Responses - **200**: Response - **401**: Response - **403**: Response - **429**: Response - **500**: Response ### GET /api/v1/ddex/messages/{reference} Operation: `getDdexMessage` Get DDEX message operation Get canonical current state, immutable hashes, validation findings, acknowledgement metadata, and authorized payload link for one message. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `reference` in path (string, required) #### Responses - **200**: Response - **401**: Response - **403**: Response - **404**: Response - **429**: Response - **500**: Response ### DELETE /api/v1/ddex/messages/{reference} Operation: `confirmDdexMessageClaim` Confirm DDEX message claim Confirm that the recipient claimed the currently available message. Claim does not mean the release is live or fully processed. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `reference` in path (string, required) - Reference: `#/components/parameters/IdempotencyKey` #### Responses - **200**: Response - **401**: Response - **403**: Response - **404**: Response - **409**: Response - **429**: Response - **500**: Response ### GET /api/v1/ddex/messages/{reference}/payload Operation: `downloadDdexPayload` Download DDEX XML payload Download the immutable generated or original native XML payload with private caching, content-type protection, and SHA-256 digest. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `reference` in path (string, required) #### Responses - **200**: The authorized immutable DDEX XML payload was returned with its checksum. **application/xml** ```json { "type": "string" } ``` - **401**: Response - **403**: Response - **404**: Response - **429**: Response - **500**: Response ### GET /api/v1/ddex/messages/{reference}/resources/{resourceReference} Operation: `downloadDdexResource` Download DDEX delivery resource Stream an authorized audio resource referenced by a generated ERN message. Supports byte ranges, immutable SHA-256 digest and ETag headers, and returns 404 after the message is superseded. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `reference` in path (string, required) - `resourceReference` in path (string, required) - `Range` in header (string): Optional RFC 7233 single byte range. #### Responses - **200**: The complete authorized resource stream. **application/octet-stream** ```json { "type": "string", "format": "binary" } ``` - **206**: The requested resource byte range. **application/octet-stream** ```json { "type": "string", "format": "binary" } ``` - **401**: Response - **403**: Response - **404**: Response - **416**: The requested byte range is invalid or outside the resource. - **429**: Response - **500**: Response ### GET /api/v1/ddex/messages/{reference}/validation-report Operation: `downloadDdexValidationReport` Download DDEX validation report Download the explainable validation report with stable findings, locations, remediation, retryability, and support correlation key. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `reference` in path (string, required) #### Responses - **200**: Response - **401**: Response - **403**: Response - **404**: Response - **429**: Response - **500**: Response ### POST /api/v1/ddex/messages/{reference}/retry Operation: `startDdexMessageRetry` Retry DDEX message operation Revalidate a blocked or failed message and queue it only when every current finding is non-blocking and the failure is retryable. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `reference` in path (string, required) - Reference: `#/components/parameters/IdempotencyKey` #### Responses - **202**: Response - **401**: Response - **403**: Response - **404**: Response - **409**: Response - **429**: Response - **500**: Response ### POST /api/v1/ddex/messages/{reference}/cancel Operation: `cancelDdexMessage` Cancel DDEX message operation Cancel work that has not been claimed by the partner. Claimed, acknowledged, or terminal message operations cannot be cancelled. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `reference` in path (string, required) - Reference: `#/components/parameters/IdempotencyKey` #### Responses - **200**: Response - **401**: Response - **403**: Response - **404**: Response - **409**: Response - **429**: Response - **500**: Response ### POST /api/v1/ddex/messages/{reference}/acknowledgements Operation: `createDdexAcknowledgement` Create DDEX acknowledgement Store an acknowledgement or processing-status payload separately from claim state while preserving the exact partner payload and checksum. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `reference` in path (string, required) - Reference: `#/components/parameters/IdempotencyKey` #### Request body Required. **application/json** ```json { "type": "object", "required": [ "type", "status", "payload" ], "properties": { "type": { "type": "string", "enum": [ "acknowledgement", "processing_status" ] }, "status": { "type": "string", "enum": [ "accepted", "rejected", "processing", "live", "takedown_complete" ] }, "partner_reference": { "type": "string", "maxLength": 191 }, "payload": { "type": "string", "maxLength": 26214400, "description": "Secure, well-formed acknowledgement XML up to 25 MiB." } } } ``` #### Responses - **202**: Response - **401**: Response - **403**: Response - **404**: Response - **409**: Response - **422**: Response - **429**: Response - **500**: Response ## Enterprise Webhooks Subscribe to signed DDEX lifecycle events, inspect delivery attempts, test receivers, replay events, and rotate reveal-once secrets. ### GET /api/v1/webhooks Operation: `listEnterpriseWebhooks` List enterprise webhooks List organization webhook subscriptions, event filters, endpoint state, and secret-rotation timestamp without returning signing secrets. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - Reference: `#/components/parameters/Page` - Reference: `#/components/parameters/PageSize` #### Responses - **200**: Response - **401**: Response - **403**: Response - **429**: Response - **500**: Response ### POST /api/v1/webhooks Operation: `createEnterpriseWebhook` Create enterprise webhook Create an HTTPS webhook subscription with DDEX event filters and return its HMAC signing secret exactly once. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - Reference: `#/components/parameters/IdempotencyKey` #### Request body Required. **application/json** ```json { "type": "object", "additionalProperties": false, "required": [ "name", "endpoint_url", "events" ], "properties": { "name": { "type": "string", "minLength": 1, "maxLength": 150 }, "endpoint_url": { "type": "string", "format": "uri", "pattern": "^https://", "maxLength": 2048 }, "events": { "type": "array", "minItems": 1, "uniqueItems": true, "items": { "type": "string", "enum": [ "ddex.delivery.status_changed", "ddex.delivery.blocked", "ddex.delivery.acknowledged", "ddex.delivery.rejected", "ddex.delivery.failed", "ddex.import.completed", "ddex.import.failed", "ddex.connection.degraded" ] } } } } ``` #### Responses - **201**: Webhook subscription created. The signing secret is returned only in this response. **application/json** ```json { "$ref": "#/components/schemas/EnterpriseWebhookSecretResult" } ``` - **401**: Response - **403**: Response - **422**: Response - **429**: Response - **500**: Response ### PATCH /api/v1/webhooks/{reference} Operation: `updateEnterpriseWebhook` Update enterprise webhook Update the webhook name, HTTPS endpoint, event filters, or active state. Set active to false to pause delivery without deleting audit history. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `reference` in path (string, required) - Reference: `#/components/parameters/IdempotencyKey` #### Request body Required. **application/json** ```json { "type": "object", "additionalProperties": false, "minProperties": 1, "properties": { "name": { "type": "string", "minLength": 1, "maxLength": 150 }, "endpoint_url": { "type": "string", "format": "uri", "pattern": "^https://", "maxLength": 2048 }, "events": { "type": "array", "minItems": 1, "uniqueItems": true, "items": { "type": "string", "enum": [ "ddex.delivery.status_changed", "ddex.delivery.blocked", "ddex.delivery.acknowledged", "ddex.delivery.rejected", "ddex.delivery.failed", "ddex.import.completed", "ddex.import.failed", "ddex.connection.degraded" ] } }, "active": { "type": "boolean" } } } ``` #### Responses - **200**: Webhook subscription updated. **application/json** ```json { "type": "object", "additionalProperties": false, "required": [ "data" ], "properties": { "data": { "$ref": "#/components/schemas/EnterpriseWebhookSubscription" } } } ``` - **401**: Response - **403**: Response - **404**: Response - **422**: Response - **429**: Response - **500**: Response ### DELETE /api/v1/webhooks/{reference} Operation: `deleteEnterpriseWebhook` Delete enterprise webhook Permanently remove a webhook subscription and its delivery history. Pause the subscription instead when audit history must be retained. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `reference` in path (string, required) - Reference: `#/components/parameters/IdempotencyKey` #### Responses - **200**: Webhook subscription and its delivery history deleted. **application/json** ```json { "type": "object", "additionalProperties": false, "required": [ "success", "deleted", "reference" ], "properties": { "success": { "type": "boolean", "const": true }, "deleted": { "type": "boolean", "const": true }, "reference": { "type": "string", "format": "uuid" } } } ``` - **401**: Response - **403**: Response - **404**: Response - **429**: Response - **500**: Response ### POST /api/v1/webhooks/{reference}/rotate-secret Operation: `updateEnterpriseWebhookSecret` Rotate webhook signing secret Replace a webhook HMAC signing secret and return the new value exactly once for secure receiver configuration. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `reference` in path (string, required) - Reference: `#/components/parameters/IdempotencyKey` #### Responses - **200**: Webhook signing secret rotated. The replacement secret is returned only in this response. **application/json** ```json { "$ref": "#/components/schemas/EnterpriseWebhookSecretResult" } ``` - **401**: Response - **403**: Response - **404**: Response - **429**: Response - **500**: Response ### POST /api/v1/webhooks/{reference}/test Operation: `createEnterpriseWebhookTest` Create test webhook delivery Queue a signed test event through the normal webhook delivery, retry, logging, and replay-protection contract. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `reference` in path (string, required) - Reference: `#/components/parameters/IdempotencyKey` #### Responses - **202**: Response - **401**: Response - **403**: Response - **404**: Response - **429**: Response - **500**: Response ### GET /api/v1/webhooks/{reference}/deliveries Operation: `listEnterpriseWebhookDeliveries` List webhook delivery attempts List event delivery references, attempts, response status, retry timing, and final delivery state for one subscription. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `reference` in path (string, required) - Reference: `#/components/parameters/Page` - Reference: `#/components/parameters/PageSize` #### Responses - **200**: Response - **401**: Response - **403**: Response - **404**: Response - **429**: Response - **500**: Response ### POST /api/v1/webhooks/{reference}/deliveries/{deliveryReference}/replay Operation: `createEnterpriseWebhookReplay` Replay enterprise webhook delivery Create a new signed delivery attempt from a prior event while preserving the original delivery reference for audit and deduplication. Security: ```json [ { "BearerAuth": [] } ] ``` #### Parameters - `reference` in path (string, required) - `deliveryReference` in path (string, required) - Reference: `#/components/parameters/IdempotencyKey` #### Responses - **202**: Response - **401**: Response - **403**: Response - **404**: Response - **409**: Response - **429**: Response - **500**: Response ## Component schemas ```json { "PublicDataEnvelope": { "type": "object", "additionalProperties": false, "required": [ "data" ], "properties": { "data": { "type": "object", "additionalProperties": true, "description": "The public resource represented by this operation. See the response example for its fields." } } }, "NestedPaginatorEnvelope": { "type": "object", "additionalProperties": false, "required": [ "data" ], "properties": { "data": { "type": "object", "additionalProperties": true, "required": [ "current_page", "data", "last_page", "per_page", "total" ], "properties": { "current_page": { "type": "integer", "minimum": 1 }, "data": { "type": "array", "items": { "type": "object", "additionalProperties": true }, "description": "Records on the current page." }, "last_page": { "type": "integer", "minimum": 1 }, "per_page": { "type": "integer", "minimum": 1, "maximum": 100 }, "total": { "type": "integer", "minimum": 0 } } } } }, "DdexFinding": { "type": "object", "additionalProperties": false, "required": [ "reference", "code", "family", "severity", "stage", "retryable", "explanation", "correlation_key" ], "properties": { "reference": { "type": "string", "format": "uuid", "description": "Stable public finding reference." }, "code": { "type": "string", "example": "DDEX_DPID_MISMATCH", "description": "Stable machine-readable validation code." }, "family": { "type": "string", "example": "identity", "description": "Validation error family." }, "severity": { "type": "string", "enum": [ "error", "warning", "info" ], "description": "Whether the finding blocks processing." }, "stage": { "type": "string", "description": "Processing stage that produced the finding." }, "retryable": { "type": "boolean", "description": "Whether retrying unchanged input can reasonably succeed." }, "location": { "type": [ "string", "null" ], "description": "JSON Pointer for REST input or XPath for native XML." }, "explanation": { "type": "string", "description": "Human-readable reason for the finding." }, "remediation": { "type": [ "string", "null" ], "description": "Recommended client action." }, "correlation_key": { "type": "string", "description": "Support-safe correlation key for this operation." } } }, "DdexOperation": { "type": "object", "additionalProperties": false, "required": [ "data", "status_url", "correlation_key" ], "properties": { "data": { "type": "object", "additionalProperties": false, "required": [ "reference", "status", "review_status", "transport_status", "partner_status", "findings" ], "properties": { "reference": { "type": "string", "format": "uuid", "description": "Stable public DDEX operation reference." }, "status": { "type": "string", "description": "Current control-plane state." }, "review_status": { "type": "string", "description": "SpaceMedia review state. Direct partner routes return not_required." }, "transport_status": { "type": "string", "description": "Transport state kept separate from review and partner processing." }, "partner_status": { "type": "string", "description": "Latest explicit processing state reported by the partner." }, "findings": { "type": "array", "items": { "$ref": "#/components/schemas/DdexFinding" } } } }, "status_url": { "type": "string", "description": "Canonical API path for polling current state." }, "correlation_key": { "type": "string", "description": "Support-safe correlation key." } } }, "DdexOperationInput": { "type": "object", "additionalProperties": false, "properties": { "connection_reference": { "type": "string", "format": "uuid", "description": "Versioned partner connection to use." }, "release_reference": { "type": "string", "format": "uuid", "description": "SpaceMedia release to snapshot and package." }, "native_xml": { "type": "string", "maxLength": 26214400, "description": "Native ERN XML up to 25 MiB, preserved byte-for-byte by the gateway." }, "deal_profile_reference": { "type": "string", "format": "uuid", "description": "Explicit commercial deal profile for this operation." }, "action": { "type": "string", "enum": [ "insert", "update", "territorial_takedown", "global_takedown", "purge" ], "description": "Requested DDEX lifecycle action." }, "metadata_overlay": { "type": "object", "additionalProperties": true, "description": "Versioned DDEX-only metadata that is absent from the release model." } }, "required": [ "connection_reference", "action" ], "oneOf": [ { "required": [ "release_reference" ] }, { "required": [ "native_xml" ] } ], "example": { "connection_reference": "3bc1f628-60af-4db2-b984-321c1525df20", "release_reference": "e781f408-69ed-469f-bfd5-082553048498", "deal_profile_reference": "91150ca4-aad3-4b5a-b041-d1cbd76d1421", "action": "insert" } }, "DdexConnection": { "type": "object", "additionalProperties": false, "required": [ "reference", "name", "partner_name", "commercial_route", "direction", "environment", "status", "review_status", "conformance_status", "transport_enabled", "local_dpid", "remote_dpid", "ern_version", "release_profile", "avs_version", "choreography", "hosting_mode", "auth_type", "capabilities", "health", "version", "credentials_configured" ], "properties": { "reference": { "type": "string", "format": "uuid" }, "name": { "type": "string" }, "partner_name": { "type": "string" }, "commercial_route": { "type": "string", "enum": [ "spacemedia_delivery_deal", "direct_partner" ] }, "direction": { "type": "string", "enum": [ "outbound", "inbound", "bidirectional" ] }, "environment": { "type": "string", "enum": [ "sandbox", "live" ] }, "status": { "type": "string", "enum": [ "draft", "pending_review", "testing", "approved", "active", "rejected", "suspended", "superseded" ] }, "review_status": { "type": "string", "enum": [ "not_submitted", "pending", "in_review", "approved", "rejected" ] }, "conformance_status": { "type": "string", "enum": [ "not_started", "testing", "passed", "failed" ] }, "conformance_evidence_reference": { "type": [ "string", "null" ] }, "transport_enabled": { "type": "boolean" }, "local_dpid": { "type": "string" }, "remote_dpid": { "type": "string" }, "ern_version": { "type": "string" }, "release_profile": { "type": "string" }, "avs_version": { "type": "string" }, "choreography": { "type": "string", "enum": [ "web_service_1_8", "cloud_storage_1_8_1" ] }, "hosting_mode": { "type": "string", "enum": [ "spacemedia_managed", "partner_managed" ] }, "auth_type": { "type": "string", "enum": [ "basic", "bearer", "sftp_password", "sftp_key" ] }, "agreement_reference": { "type": [ "string", "null" ] }, "capabilities": { "type": [ "array", "null" ], "items": { "type": "string" } }, "health": { "type": "object", "additionalProperties": false, "required": [ "status", "checked_at" ], "properties": { "status": { "type": "string", "enum": [ "unknown", "healthy", "degraded" ] }, "checked_at": { "type": [ "string", "null" ], "format": "date-time" } } }, "version": { "type": "integer", "minimum": 1 }, "credentials_configured": { "type": "boolean" }, "credentials_rotated_at": { "type": [ "string", "null" ], "format": "date-time" }, "activation_requested_at": { "type": [ "string", "null" ], "format": "date-time" }, "conformance_checked_at": { "type": [ "string", "null" ], "format": "date-time" }, "reviewed_at": { "type": [ "string", "null" ], "format": "date-time" }, "activated_at": { "type": [ "string", "null" ], "format": "date-time" }, "readiness": { "type": "object", "additionalProperties": true, "description": "Applicable activation checks and remediation. Platform approval evidence is not exposed." } } }, "DdexConnectionResult": { "type": "object", "additionalProperties": false, "required": [ "data", "secret_values_returned" ], "properties": { "data": { "$ref": "#/components/schemas/DdexConnection" }, "secret_values_returned": { "type": "boolean", "const": false, "description": "DDEX partner credentials are accepted for storage but are never returned." } }, "example": { "data": { "reference": "3bc1f628-60af-4db2-b984-321c1525df20", "name": "Partner sandbox", "partner_name": "Example DSP", "commercial_route": "direct_partner", "direction": "outbound", "environment": "sandbox", "status": "draft", "review_status": "not_submitted", "conformance_status": "not_started", "transport_enabled": false, "local_dpid": "PA-DPIDA-2026073001-N", "remote_dpid": "PA-DPIDA-2026073002-N", "ern_version": "4.3.2", "release_profile": "Audio", "avs_version": "011", "choreography": "web_service_1_8", "hosting_mode": "partner_managed", "auth_type": "bearer", "capabilities": [ "insert", "update", "global_takedown" ], "health": { "status": "unknown", "checked_at": null }, "version": 1, "credentials_configured": true, "credentials_rotated_at": "2026-07-30T15:10:00Z" }, "secret_values_returned": false } }, "EnterpriseWebhookSubscription": { "type": "object", "additionalProperties": true, "required": [ "reference", "name", "endpoint_url", "events", "active", "secret_configured", "secret_rotated_at", "previous_secret_valid_until", "created_at" ], "properties": { "reference": { "type": "string", "format": "uuid" }, "name": { "type": "string" }, "endpoint_url": { "type": "string", "format": "uri", "pattern": "^https://" }, "events": { "type": "array", "minItems": 1, "uniqueItems": true, "items": { "type": "string", "enum": [ "ddex.delivery.status_changed", "ddex.delivery.blocked", "ddex.delivery.acknowledged", "ddex.delivery.rejected", "ddex.delivery.failed", "ddex.import.completed", "ddex.import.failed", "ddex.connection.degraded" ] } }, "active": { "type": "boolean" }, "secret_configured": { "type": "boolean" }, "secret_rotated_at": { "type": [ "string", "null" ], "format": "date-time" }, "previous_secret_valid_until": { "type": [ "string", "null" ], "format": "date-time", "description": "During rotation, outgoing signatures include both current and previous HMAC values until this time." }, "created_at": { "type": [ "string", "null" ], "format": "date-time" } }, "example": { "reference": "9f6529b3-218a-478f-a074-0830165889c5", "name": "DDEX operations", "endpoint_url": "https://integrator.example/webhooks/spacemedia", "events": [ "ddex.delivery.status_changed", "ddex.delivery.failed" ], "active": true, "secret_configured": true, "secret_rotated_at": "2026-07-30T15:40:00Z", "previous_secret_valid_until": null, "created_at": "2026-07-30T15:40:00Z" } }, "EnterpriseWebhookSecretResult": { "type": "object", "additionalProperties": false, "required": [ "data", "secret_values_returned" ], "properties": { "data": { "allOf": [ { "$ref": "#/components/schemas/EnterpriseWebhookSubscription" }, { "type": "object", "required": [ "signing_secret" ], "properties": { "signing_secret": { "type": "string", "format": "password", "writeOnly": true, "x-sensitive": true, "description": "Reveal-once signing secret. Store it immediately and never log it." } } } ] }, "secret_values_returned": { "type": "boolean", "const": true } }, "example": { "data": { "reference": "9f6529b3-218a-478f-a074-0830165889c5", "name": "DDEX operations", "endpoint_url": "https://integrator.example/webhooks/spacemedia", "events": [ "ddex.delivery.status_changed", "ddex.delivery.failed" ], "active": true, "secret_configured": true, "secret_rotated_at": "2026-07-30T15:40:00Z", "previous_secret_valid_until": null, "created_at": "2026-07-30T15:40:00Z", "signing_secret": "smwh_example_store_securely_and_never_log" }, "secret_values_returned": true } }, "ApiError": { "type": "object", "additionalProperties": true, "required": [ "success", "message" ], "properties": { "success": { "type": "boolean", "example": false, "description": "Whether the API request completed successfully." }, "message": { "type": "string", "example": "Validation failed.", "description": "Human-readable outcome or error message suitable for logs and operator interfaces." }, "errors": { "type": "object", "additionalProperties": true, "properties": { "title": { "type": "array", "items": { "type": "string", "example": "The title field is required." }, "description": "Catalog or content title shown in the dashboard and API responses." } }, "description": "Validation errors keyed by request field. Each entry contains one or more human-readable messages." }, "error_code": { "type": "string", "description": "Stable machine-readable failure code when the error was reported by an application workflow." }, "error_reference": { "type": "string", "format": "uuid", "description": "Support-safe reference for a reported server failure." } }, "description": "ApiError object returned by the public organization API." }, "User": { "type": "object", "additionalProperties": false, "required": [ "user_id", "name", "email", "verified", "is_invited", "is_suspended" ], "properties": { "user_id": { "type": "string", "example": "7d2d9f72-c0a2-4d4b-9b6d-7caa942b8a71", "format": "uuid", "description": "Stable public user reference. Use this value in related endpoint paths and request bodies." }, "name": { "type": "string", "example": "Maya Chen", "description": "Display name for this user." }, "full_name": { "type": "string", "example": "Maya Chen", "description": "Full display name assembled from the account profile fields." }, "first_name": { "type": "string", "example": "Maya", "description": "Given name for the user or member profile." }, "last_name": { "type": "string", "example": "Chen", "description": "Family name for the user or member profile." }, "email": { "type": "string", "example": "maya.chen@northstar-distribution.co.uk", "description": "Email address associated with the account or invitation." }, "phone": { "type": "string", "example": "+442071838750", "description": "Phone number on the account profile when provided." }, "language": { "type": "string", "example": "en", "description": "Primary language value used for profile, release, or track metadata." }, "country": { "type": "string", "example": "United Kingdom", "description": "Country associated with the user, artist, or organization record." }, "profile_photo": { "type": "string", "example": "https://assets.spacemedia-docs.invalid/users/maya-chen/profile-photo.webp", "format": "uri", "description": "Public media URL or asset reference for the uploaded image." }, "verified": { "type": "boolean", "example": true, "description": "Whether the account email or identity state is verified." }, "email_verified_at": { "type": "string", "example": "2026-06-25T08:15:00+00:00", "format": "date-time", "description": "Timestamp for when email verified occurred, formatted as ISO 8601 when available." }, "last_login_at": { "type": "string", "example": "2026-07-04T10:15:00+00:00", "format": "date-time", "description": "Timestamp for when last login occurred, formatted as ISO 8601 when available." }, "invitation_status": { "type": "string", "example": "accepted", "description": "Invitation lifecycle status, such as pending or accepted." }, "is_invited": { "type": "boolean", "example": false, "description": "Whether this user was created through an organization invitation." }, "is_suspended": { "type": "boolean", "example": false, "description": "Whether organization access is currently suspended for this account." }, "roles": { "type": "array", "items": { "type": "object", "additionalProperties": true, "properties": { "role_id": { "type": "string", "example": "c0f1c68c-7c2f-4954-b52c-9d7e5eb46d3e", "format": "uuid", "description": "Stable public role reference. Use this value in related endpoint paths and request bodies." }, "name": { "type": "string", "example": "Catalog Manager", "description": "Display name for this user." } } }, "description": "Roles assigned to the user or member within the organization." }, "organization_name": { "type": "string", "example": "Northstar Distribution", "description": "Organization display name shown for context. This is not an organization identifier and cannot be used to switch organization scope." }, "created_at": { "type": "string", "example": "2026-07-04T09:30:00+00:00", "format": "date-time", "description": "Timestamp for when created occurred, formatted as ISO 8601 when available." }, "updated_at": { "type": "string", "example": "2026-07-04T10:15:00+00:00", "format": "date-time", "description": "Timestamp for when updated occurred, formatted as ISO 8601 when available." } }, "description": "User object returned by the public organization API." }, "Artist": { "type": "object", "additionalProperties": false, "required": [ "artist_id", "name" ], "properties": { "artist_id": { "type": "string", "example": "6f209ac7-d82c-4c8f-9d3e-bfe39c0df802", "format": "uuid", "description": "Stable public artist reference. Use this value in related endpoint paths and request bodies." }, "name": { "type": "string", "example": "Nova Vale", "description": "Display name for this artist." }, "artist_type": { "type": "string", "example": "Primary Artist", "description": "Artist classification used for DSP metadata and credit display." }, "spotify_id": { "type": "string", "example": "3mY7kJqR8B2nQvP6LxT4Za", "description": "Optional external Spotify artist reference for matching catalog profiles. It is not a SpaceMedia API path reference; use artist_id for SpaceMedia API calls." }, "bio": { "type": "string", "example": "Electronic artist and producer from London.", "description": "Artist biography or descriptive profile text." }, "country": { "type": "string", "example": "GB", "description": "Country associated with the user, artist, or organization record." }, "releases_count": { "type": "integer", "example": 2, "description": "Number of releases currently associated with the artist." }, "tracks_count": { "type": "integer", "example": 7, "description": "Number of tracks currently associated with the artist." }, "total_streams": { "type": "integer", "example": 125000, "description": "Total reported streams when reporting data is available." }, "created_at": { "type": "string", "example": "2026-06-01T11:00:00+00:00", "format": "date-time", "description": "Timestamp for when created occurred, formatted as ISO 8601 when available." }, "updated_at": { "type": "string", "example": "2026-07-04T10:15:00+00:00", "format": "date-time", "description": "Timestamp for when updated occurred, formatted as ISO 8601 when available." } }, "description": "Artist object returned by the public organization API." }, "Release": { "type": "object", "additionalProperties": false, "required": [ "release_id", "title", "status", "artists" ], "properties": { "release_id": { "type": "string", "example": "b7a15d95-58f6-4f67-b5d1-89f4f5bfb4d8", "format": "uuid", "description": "Stable public release reference. Use this value in related endpoint paths and request bodies." }, "title": { "type": "string", "example": "Midnight Atlas", "description": "Catalog or content title shown in the dashboard and API responses." }, "status": { "type": "string", "example": "draft", "description": "Current lifecycle status for this record." }, "format": { "type": "string", "example": "single", "description": "Release format, such as single, EP, or album." }, "label": { "type": "string", "example": "Night Shift Records", "description": "Label name attached to the release metadata." }, "genre": { "type": "string", "example": "Electronic", "description": "Primary release or track genre selected from supported values." }, "secondary_genre": { "type": "string", "example": "Ambient", "description": "Optional secondary genre used for more precise metadata." }, "language": { "type": "string", "example": "English", "description": "Primary language value used for profile, release, or track metadata." }, "explicit_content": { "type": "boolean", "example": false, "description": "Whether the release or track is marked as explicit." }, "upc_code": { "type": "string", "example": "5054429191012", "description": "UPC assigned to the release, or null when it has not been assigned yet." }, "reference_number": { "type": "string", "example": "NSD-2026-041", "description": "Human-readable catalog or billing reference shown in the dashboard." }, "scheduled_date": { "type": "string", "example": "2026-08-21", "format": "date", "description": "Scheduled release date used for delivery planning and catalog display." }, "original_release_date": { "type": "string", "example": "2026-08-21", "format": "date", "description": "Calendar date for original release." }, "copyright_detection_enabled": { "type": "boolean", "example": true, "description": "Whether copyright checking is enabled for the organization or release workflow." }, "price_category": { "type": "string", "example": "mid", "description": "Release price tier or commercial category used for store delivery and billing decisions." }, "territories": { "type": "array", "items": { "type": "string", "example": "GB" }, "description": "Territory codes where the release or rights metadata should apply." }, "distribution": { "type": "array", "items": { "type": "object", "additionalProperties": true, "properties": { "channel": { "type": "string", "example": "spotify", "description": "Delivery channel or store identifier using public snake_case values." }, "status": { "type": "string", "example": "selected", "description": "Current lifecycle status for this record." } } }, "description": "Delivery destinations and their organization-visible status values." }, "cover_art": { "type": "string", "example": "https://assets.spacemedia-docs.invalid/releases/midnight-atlas/cover.jpg", "format": "uri", "description": "Public media URL or asset reference for the uploaded image." }, "track_count": { "type": "integer", "example": 1, "description": "Number of track records visible in this context." }, "release_review": { "type": [ "object", "null" ], "additionalProperties": false, "properties": { "review_id": { "type": "string", "example": "f07b26d4-4ab6-4b46-8b4d-2d95c0a4f25d", "format": "uuid", "description": "Stable public review reference for the release review workflow." }, "review_status": { "type": "string", "example": "ready_for_review", "description": "Organization-visible review status for the release." }, "delivery_status": { "type": "string", "example": "pending", "description": "Organization-visible delivery status returned by the release review workflow." }, "delivery_simulated": { "type": "boolean", "example": false, "description": "True only when staging completed the delivery lifecycle locally without contacting a DSP or delivery partner." } }, "description": "Current review and delivery state when a release has entered review." }, "artists": { "type": "array", "items": { "type": "object", "additionalProperties": false, "properties": { "artist_id": { "type": "string", "example": "6f209ac7-d82c-4c8f-9d3e-bfe39c0df802", "format": "uuid", "description": "Public artist reference returned by the artists API." }, "name": { "type": "string", "example": "Nova Vale", "description": "Display name for this release." }, "type": { "type": "string", "example": "Primary Artist", "description": "Artist credit role for this release or track, such as Primary Artist or Featured Artist." } }, "required": [ "artist_id", "type" ] }, "description": "Artists credited or attached to this catalog record." }, "created_by": { "type": "object", "additionalProperties": true, "properties": { "user_id": { "type": "string", "example": "7d2d9f72-c0a2-4d4b-9b6d-7caa942b8a71", "format": "uuid", "description": "Stable public user reference. Use this value in related endpoint paths and request bodies." }, "name": { "type": "string", "example": "Maya Chen", "description": "Display name for this release." }, "email": { "type": "string", "example": "maya.chen@northstar-distribution.co.uk", "description": "Email address associated with the account or invitation." } }, "description": "User that created the record when available to the current organization." }, "created_at": { "type": "string", "example": "2026-07-04T09:30:00+00:00", "format": "date-time", "description": "Timestamp for when created occurred, formatted as ISO 8601 when available." }, "updated_at": { "type": "string", "example": "2026-07-04T10:15:00+00:00", "format": "date-time", "description": "Timestamp for when updated occurred, formatted as ISO 8601 when available." } }, "description": "Release object returned by the public organization API." }, "Track": { "type": "object", "additionalProperties": false, "required": [ "track_id", "title", "artists", "documents_requested" ], "properties": { "track_id": { "type": "string", "example": "e454b6f8-df5b-49db-9b9f-916f74ec1f21", "format": "uuid", "description": "Stable public track reference. Use this value in related endpoint paths and request bodies." }, "release": { "type": "object", "additionalProperties": true, "properties": { "release_id": { "type": "string", "example": "b7a15d95-58f6-4f67-b5d1-89f4f5bfb4d8", "format": "uuid", "description": "Stable public release reference. Use this value in related endpoint paths and request bodies." }, "title": { "type": "string", "example": "Midnight Atlas", "description": "Catalog or content title shown in the dashboard and API responses." }, "status": { "type": "string", "example": "draft", "description": "Current lifecycle status for this record." } }, "description": "Release summary or nested release object connected to this workflow." }, "title": { "type": "string", "example": "Midnight Atlas", "description": "Catalog or content title shown in the dashboard and API responses." }, "artists": { "type": "array", "items": { "type": "object", "additionalProperties": false, "properties": { "artist_id": { "type": "string", "example": "6f209ac7-d82c-4c8f-9d3e-bfe39c0df802", "format": "uuid", "description": "Public artist reference returned by the artists API." }, "name": { "type": "string", "example": "Nova Vale", "description": "Display name for this track." }, "type": { "type": "string", "example": "Primary Artist", "description": "Artist credit role for this release or track, such as Primary Artist or Featured Artist." } }, "required": [ "artist_id", "type" ] }, "description": "Artists credited or attached to this catalog record." }, "duration": { "type": "integer", "example": 196, "description": "Track duration in seconds or a display-ready duration value." }, "language": { "type": "string", "example": "English", "description": "Primary language value used for profile, release, or track metadata." }, "primary_genre": { "type": "string", "example": "Electronic", "description": "Primary track genre selected from supported values." }, "secondary_genre": { "type": "string", "example": "Ambient", "description": "Optional secondary genre used for more precise metadata." }, "track_version": { "type": "string", "example": "Original Mix", "description": "Version label for the track, such as remix, radio edit, instrumental, or acoustic version." }, "isrc_code": { "type": "string", "example": "GBSMU2600001", "description": "ISRC assigned to the track, or blank when one should be assigned later." }, "iswc_code": { "type": "string", "example": "T0345246801", "description": "ISWC for the composition when available." }, "is_available_separately": { "type": "boolean", "example": true, "description": "Whether the track can be distributed or sold separately from the release when supported by selected stores." }, "is_parental_advisory": { "type": "boolean", "example": false, "description": "Whether the track should be marked with an explicit or parental advisory flag." }, "license_holder_year": { "type": "integer", "example": 2026, "description": "Year associated with the rights holder for the release or track metadata." }, "license_holder_name": { "type": "string", "example": "Night Shift Records Ltd", "description": "Legal name of the person or company that holds the relevant rights for the release or track." }, "playback_url": { "type": "string", "example": "https://media.spacemedia-docs.invalid/audio/midnight-atlas/master.wav", "format": "uri", "description": "Public URL returned for this resource or action." }, "preview_url": { "type": "string", "example": "https://media.spacemedia-docs.invalid/audio/midnight-atlas/preview.mp3", "format": "uri", "description": "Public URL returned for this resource or action." }, "documents_requested": { "type": "boolean", "example": false, "description": "Whether the track currently requires supporting rights or copyright documentation before review can continue." }, "created_at": { "type": "string", "example": "2026-07-04T09:30:00+00:00", "format": "date-time", "description": "Timestamp for when created occurred, formatted as ISO 8601 when available." }, "updated_at": { "type": "string", "example": "2026-07-04T10:15:00+00:00", "format": "date-time", "description": "Timestamp for when updated occurred, formatted as ISO 8601 when available." } }, "description": "Track object returned by the public organization API." }, "TrackUploadStatus": { "description": "Current state of a resumable track upload. Completed uploads include the audio_file_id required by track create and update requests.", "oneOf": [ { "type": "object", "additionalProperties": false, "required": [ "success", "complete", "upload_session_id", "state", "received_chunks", "total_chunks", "expires_at" ], "properties": { "success": { "type": "boolean", "const": true }, "complete": { "type": "boolean", "const": false }, "upload_session_id": { "type": "string", "pattern": "^[A-Za-z0-9_-]{1,80}$" }, "state": { "type": "string", "enum": [ "receiving", "assembling" ] }, "received_chunks": { "type": "array", "items": { "type": "integer", "minimum": 0 } }, "total_chunks": { "type": "integer", "minimum": 1, "maximum": 64 }, "expires_at": { "type": "string", "format": "date-time" }, "message": { "type": "string" } } }, { "type": "object", "additionalProperties": false, "required": [ "success", "complete", "upload_session_id", "audio_file_id", "file_name", "original", "links", "extensions", "duration", "mime_type", "checksum" ], "properties": { "success": { "type": "boolean", "const": true }, "complete": { "type": "boolean", "const": true }, "upload_session_id": { "type": "string", "pattern": "^[A-Za-z0-9_-]{1,80}$" }, "audio_file_id": { "type": "string", "description": "Temporary audio reference to pass when creating or updating a track." }, "file_name": { "type": "string" }, "original": { "type": "string" }, "links": { "type": "array", "items": { "type": "string", "format": "uri" } }, "extensions": { "type": "object", "additionalProperties": false, "required": [ "input", "output" ], "properties": { "input": { "type": "string" }, "output": { "type": "string" } } }, "duration": { "type": [ "integer", "null" ], "minimum": 0 }, "mime_type": { "type": [ "string", "null" ] }, "checksum": { "type": [ "string", "null" ] } } } ] }, "RevenueSplit": { "type": "object", "additionalProperties": false, "required": [ "split_id", "title", "percentage", "locked" ], "properties": { "split_id": { "type": "string", "example": "8df80f4e-63df-4562-87e8-f1b2f2f0ce47", "format": "uuid", "description": "Stable public split reference. Use this value in related endpoint paths and request bodies." }, "title": { "type": "string", "example": "Midnight Atlas Producer Share", "description": "Catalog or content title shown in the dashboard and API responses." }, "percentage": { "type": "integer", "example": 25, "description": "Revenue split percentage assigned to this beneficiary." }, "start_date": { "type": "string", "example": "2026-08-21", "format": "date", "description": "Calendar date for start." }, "end_date": { "description": "Calendar date for end.", "type": [ "string", "null" ], "format": "date" }, "locked": { "type": "boolean", "example": false, "description": "Whether the split, role, or configuration is locked from further editing in its current state." }, "beneficiary": { "type": "object", "additionalProperties": true, "properties": { "user_id": { "type": "string", "example": "43cda1b2-f7e9-49c7-b4fb-4fcfc5a02a9c", "format": "uuid", "description": "Stable public user reference. Use this value in related endpoint paths and request bodies." }, "name": { "type": "string", "example": "Eli Brooks", "description": "Display name for this revenuesplit." }, "email": { "type": "string", "example": "eli.brooks@northstar-distribution.co.uk", "description": "Email address associated with the account or invitation." } }, "description": "User or collaborator receiving the revenue split share." }, "creator": { "type": "object", "additionalProperties": true, "properties": { "user_id": { "type": "string", "example": "7d2d9f72-c0a2-4d4b-9b6d-7caa942b8a71", "format": "uuid", "description": "Stable public user reference. Use this value in related endpoint paths and request bodies." }, "name": { "type": "string", "example": "Maya Chen", "description": "Display name for this revenuesplit." }, "email": { "type": "string", "example": "maya.chen@northstar-distribution.co.uk", "description": "Email address associated with the account or invitation." } }, "description": "User summary for the person who created the record." }, "releases": { "type": "array", "items": { "type": "object", "additionalProperties": true, "properties": { "release_id": { "type": "string", "example": "b7a15d95-58f6-4f67-b5d1-89f4f5bfb4d8", "format": "uuid", "description": "Stable public release reference. Use this value in related endpoint paths and request bodies." }, "title": { "type": "string", "example": "Midnight Atlas", "description": "Catalog or content title shown in the dashboard and API responses." }, "status": { "type": "string", "example": "draft", "description": "Current lifecycle status for this record." } } }, "description": "Releases visible for the current organization and permission scope." }, "tracks": { "type": "array", "items": { "type": "object", "additionalProperties": true, "properties": { "track_id": { "type": "string", "example": "e454b6f8-df5b-49db-9b9f-916f74ec1f21", "format": "uuid", "description": "Stable public track reference. Use this value in related endpoint paths and request bodies." }, "title": { "type": "string", "example": "Midnight Atlas", "description": "Catalog or content title shown in the dashboard and API responses." } } }, "description": "Tracks included in the release or returned by the catalog query." } }, "description": "RevenueSplit object returned by the public organization API." }, "Member": { "type": "object", "additionalProperties": false, "properties": { "member_id": { "type": "string", "example": "54dbefc4-49b2-4b18-9945-0921fd07a9fd", "format": "uuid", "description": "Stable public member reference for member-management endpoints. Store and use member_id when reading, updating, suspending, unsuspending, or removing a team member." }, "first_name": { "type": "string", "example": "Eli", "description": "Given name for the user or member profile." }, "last_name": { "type": "string", "example": "Brooks", "description": "Family name for the user or member profile." }, "name": { "type": "string", "example": "Eli Brooks", "description": "Display name for this member." }, "email": { "type": "string", "example": "eli.brooks@northstar-distribution.co.uk", "description": "Email address associated with the account or invitation." }, "status": { "type": "string", "example": "active", "description": "Current lifecycle status for this record." }, "role": { "type": "object", "additionalProperties": true, "properties": { "role_id": { "type": "string", "example": "c0f1c68c-7c2f-4954-b52c-9d7e5eb46d3e", "format": "uuid", "description": "Stable public role reference. Use this value in related endpoint paths and request bodies." }, "name": { "type": "string", "example": "Catalog Manager", "description": "Display name for this member." } }, "description": "Role assigned to the user or member, including its public role reference and display name when expanded." }, "permissions": { "type": "array", "items": { "type": "string", "example": "view releases" }, "description": "Permission keys granted by this role or member assignment." }, "is_suspended": { "type": "boolean", "example": false, "description": "Whether organization access is currently suspended for this account." }, "invited_at": { "type": "string", "example": "2026-07-01T12:00:00+00:00", "format": "date-time", "description": "Timestamp for when invited occurred, formatted as ISO 8601 when available." }, "accepted_at": { "type": "string", "example": "2026-07-02T09:05:00+00:00", "format": "date-time", "description": "Timestamp for when accepted occurred, formatted as ISO 8601 when available." } }, "description": "Member object returned by the public organization API.", "required": [ "member_id", "name", "email", "status" ] }, "MemberRole": { "type": "object", "additionalProperties": false, "required": [ "role_id", "name", "protected", "permissions" ], "properties": { "role_id": { "type": "string", "example": "c0f1c68c-7c2f-4954-b52c-9d7e5eb46d3e", "format": "uuid", "description": "Stable public role reference. Use this value in related endpoint paths and request bodies." }, "name": { "type": "string", "example": "Catalog Manager", "description": "Display name for this memberrole." }, "preset": { "type": "string", "example": "catalog_manager", "description": "Optional role template used to seed permissions before custom role edits are applied." }, "protected": { "type": "boolean", "example": false, "description": "Whether the role or setting is protected from organization-level edits." }, "permissions": { "type": "array", "items": { "type": "string", "example": "view releases" }, "description": "Permission keys granted by this role or member assignment." } }, "description": "MemberRole object returned by the public organization API." }, "Subscription": { "type": "object", "additionalProperties": false, "required": [ "subscription_id", "is_active", "package", "amount", "total_paid_amount", "gateway" ], "properties": { "subscription_id": { "type": "string", "example": "ad3095e4-4628-43d0-8e47-d8996c7daf0d", "format": "uuid", "description": "Stable public subscription reference. Use this value in related endpoint paths and request bodies." }, "status": { "type": "string", "example": "active", "description": "Current lifecycle status for this record." }, "is_active": { "type": "boolean", "example": true, "description": "Whether the subscription, plan, add-on, or resource is currently active." }, "package": { "type": "object", "additionalProperties": true, "properties": { "package_id": { "type": "string", "example": "f3e184c8-8b3a-45b8-9bcb-cc12f70826b6", "format": "uuid", "description": "Stable public package reference. Use this value in related endpoint paths and request bodies." }, "name": { "type": "string", "example": "Growth Distribution Monthly", "description": "Display name for this subscription." }, "type": { "type": "string", "example": "membership", "description": "Public type or role value for this item." }, "status": { "type": "string", "example": "published", "description": "Current lifecycle status for this record." }, "price": { "type": "integer", "example": 49, "description": "price for package." }, "currency": { "type": "string", "example": "GBP", "description": "ISO currency code for the amount shown on the same object." }, "royalty_percentage": { "type": "integer", "example": 85, "description": "royalty percentage for package." }, "artist_profile_limit": { "type": "integer", "example": 25, "description": "artist profile limit for package." }, "release_limit": { "type": "integer", "example": 50, "description": "release limit for package." }, "release_limit_cycle": { "type": "string", "example": "monthly", "description": "release limit cycle for package." }, "feature_list": { "type": "array", "items": { "type": "string", "example": "Unlimited team members" }, "description": "feature list for package." } }, "description": "Membership package attached to the subscription or checkout." }, "subscribed_at": { "type": "string", "example": "2026-06-01T09:00:00+00:00", "format": "date-time", "description": "Timestamp for when subscribed occurred, formatted as ISO 8601 when available." }, "next_payment": { "type": "string", "example": "2026-08-01T09:00:00+00:00", "format": "date-time", "description": "Next scheduled payment date for the subscription when available." }, "amount": { "type": "integer", "example": 49, "description": "Monetary amount in the currency shown on the same object." }, "total_paid_amount": { "type": "integer", "example": 98, "description": "Monetary amount in the currency shown on the same object." }, "gateway": { "type": "string", "example": "stripe", "description": "Payment gateway used for this checkout or billing flow.", "enum": [ "airwallex", "stripe", "paypal" ] } }, "description": "Subscription object returned by the public organization API." }, "Checkout": { "type": "object", "additionalProperties": false, "required": [ "checkout_id", "gateway", "status" ], "properties": { "checkout_id": { "type": "string", "example": "39b189c1-8f8e-4df2-8632-176f87f791a1", "format": "uuid", "description": "Stable public checkout reference. Use this value in related endpoint paths and request bodies." }, "gateway": { "type": "string", "example": "airwallex", "description": "Payment gateway used for this checkout or billing flow.", "enum": [ "airwallex", "stripe", "paypal" ] }, "status": { "type": "string", "example": "pending", "description": "Current lifecycle status for this record." }, "redirect_url": { "type": "string", "example": "https://checkout.spacemedia-docs.invalid/session/docs-checkout-session", "format": "uri", "description": "Hosted checkout or management URL where the user should continue the flow." }, "embedded_checkout_token": { "type": "string", "example": "docs_invalid_embedded_checkout_token", "description": "Short-lived embedded checkout token. Treat this value as sensitive payment data and never log it or expose it in support tickets.", "format": "password", "x-sensitive": true }, "amount": { "type": "integer", "example": 49, "description": "Monetary amount in the currency shown on the same object." }, "currency": { "type": "string", "example": "GBP", "description": "ISO currency code for the amount shown on the same object." }, "expires_at": { "type": "string", "example": "2026-07-04T10:30:00+00:00", "format": "date-time", "description": "Timestamp for when expires occurred, formatted as ISO 8601 when available." } }, "description": "Checkout object returned by the public organization API." }, "Smartlink": { "type": "object", "additionalProperties": false, "required": [ "smartlink_id", "slug", "title", "status", "destinations" ], "properties": { "smartlink_id": { "type": "string", "example": "1fdf8564-81f7-4607-9c8b-154b62db8d5f", "format": "uuid", "description": "Stable public smartlink reference. Use this value in related endpoint paths and request bodies." }, "release": { "type": "object", "additionalProperties": true, "properties": { "release_id": { "type": "string", "example": "b7a15d95-58f6-4f67-b5d1-89f4f5bfb4d8", "format": "uuid", "description": "Stable public release reference. Use this value in related endpoint paths and request bodies." }, "title": { "type": "string", "example": "Midnight Atlas", "description": "Catalog or content title shown in the dashboard and API responses." }, "status": { "type": "string", "example": "draft", "description": "Current lifecycle status for this record." } }, "description": "Release summary or nested release object connected to this workflow." }, "slug": { "type": "string", "example": "nova-vale-midnight-atlas", "description": "URL-safe slug used for public links or add-on references." }, "title": { "type": "string", "example": "Midnight Atlas", "description": "Catalog or content title shown in the dashboard and API responses." }, "status": { "type": "string", "example": "published", "description": "Current lifecycle status for this record." }, "public_url": { "type": "string", "example": "https://links.northstar-distribution.co.uk/nova-vale-midnight-atlas", "format": "uri", "description": "Public URL returned for this resource or action." }, "destinations": { "type": "array", "items": { "type": "object", "additionalProperties": false, "properties": { "platform": { "type": "string", "example": "spotify", "description": "Streaming platform or destination key, such as spotify, apple_music, youtube_music, or deezer." }, "url": { "type": "string", "example": "https://open.spotify.com/album/4Gj9kL2mN8rT6bY1xQvP3z", "format": "uri", "description": "Public URL returned for this resource or action." }, "enabled": { "type": "boolean", "example": true, "description": "Whether this option or destination is currently enabled." } }, "required": [ "platform", "url" ] }, "description": "DSP and landing-page destination objects shown on the smartlink." }, "clicks": { "type": "integer", "example": 1840, "description": "Number of recorded smartlink clicks for the selected period or destination." }, "conversion_rate": { "type": "number", "example": 0.18, "description": "Percentage of visitors who clicked through or completed the measured smartlink action." }, "updated_at": { "type": "string", "example": "2026-07-04T10:15:00+00:00", "format": "date-time", "description": "Timestamp for when updated occurred, formatted as ISO 8601 when available." } }, "description": "Smartlink object returned by the public organization API." } } ``` # SpaceMedia Reports API OpenAPI contract The SpaceMedia Reports API powers royalty reporting, import, analytics, export, reconciliation, dispute, and payout operations. This contract contains only implemented guarded routes. A route remains unavailable unless its deployment feature flag and tenant access policy are enabled. Canonical source: https://docs.spacemedia.uk/reports-api/openapi.json ## Identity Human identity, invitation, session, and logout operations. ### POST /platform/v1/identity/login Operation: `loginPlatformIdentity` Establish a tenant-scoped human session. Security: ```json [] ``` #### Parameters - Reference: `#/components/parameters/CsrfToken` #### Request body Required. **application/json** ```json { "$ref": "#/components/schemas/LoginRequest" } ``` #### Responses - **200**: Response - **401**: Response - **422**: Response - **429**: Response ### POST /platform/v1/identity/invitations/accept Operation: `acceptNewPlatformInvitation` Accept an invitation and create a new verified identity. Security: ```json [] ``` #### Parameters - Reference: `#/components/parameters/CsrfToken` #### Request body Required. **application/json** ```json { "$ref": "#/components/schemas/AcceptNewInvitationRequest" } ``` #### Responses - **201**: Response - **422**: Response - **429**: Response ### POST /platform/v1/identity/invitations/accept-existing Operation: `acceptExistingPlatformInvitation` Accept an invitation as the current step-up-authenticated identity. Security: ```json [ { "platformSession": [] } ] ``` #### Parameters - Reference: `#/components/parameters/CsrfToken` #### Request body Required. **application/json** ```json { "$ref": "#/components/schemas/AcceptExistingInvitationRequest" } ``` #### Responses - **201**: Membership activated. **application/json** ```json { "$ref": "#/components/schemas/InvitationAcceptanceResponse" } ``` - **401**: Response - **403**: Response - **422**: Response - **429**: Response ### GET /platform/v1/identity/session Operation: `getPlatformIdentitySession` Return the current opaque identity and tenant session. Security: ```json [ { "platformSession": [] } ] ``` #### Responses - **200**: Response - **401**: Response ### GET /platform/v1/identity/sessions Operation: `listPlatformIdentitySessions` List the current identity's bounded tenant session history. Security: ```json [ { "platformSession": [] } ] ``` #### Responses - **200**: Current and recent privacy-safe session inventory. **application/json** ```json { "$ref": "#/components/schemas/IdentitySessionPageResponse" } ``` - **401**: Response ### POST /platform/v1/identity/sessions/{session}/revoke Operation: `revokePlatformIdentitySession` Revoke another owned session after fresh non-recovery step-up. Security: ```json [ { "platformSession": [] } ] ``` #### Parameters - Reference: `#/components/parameters/IdentitySessionPath` - Reference: `#/components/parameters/CsrfToken` #### Request body Required. **application/json** ```json { "$ref": "#/components/schemas/RevokeIdentitySessionRequest" } ``` #### Responses - **200**: Session revoked or its prior revocation replayed. **application/json** ```json { "$ref": "#/components/schemas/IdentitySessionRevocationResponse" } ``` - **401**: Response - **403**: Response - **422**: Response - **429**: Response ### POST /platform/v1/identity/logout Operation: `logoutPlatformIdentity` Revoke the current platform session. Security: ```json [ { "platformSession": [] } ] ``` #### Parameters - Reference: `#/components/parameters/CsrfToken` #### Responses - **204**: Session revoked. Response has no body. - **401**: Response ## MFA Multi-factor enrollment, challenge, and recovery operations. ### POST /platform/v1/identity/mfa/enroll Operation: `startPlatformMfaEnrollment` Start initial TOTP enrollment and return the secret once. Security: ```json [ { "platformSession": [] } ] ``` #### Parameters - Reference: `#/components/parameters/CsrfToken` #### Request body Required. **application/json** ```json { "$ref": "#/components/schemas/StartMfaEnrollmentRequest" } ``` #### Responses - **201**: Pending TOTP enrollment. **application/json** ```json { "$ref": "#/components/schemas/MfaEnrollmentResponse" } ``` - **401**: Response - **422**: Response - **429**: Response ### POST /platform/v1/identity/mfa/confirm Operation: `confirmPlatformMfaEnrollment` Confirm initial TOTP enrollment and return recovery codes once. Security: ```json [ { "platformSession": [] } ] ``` #### Parameters - Reference: `#/components/parameters/CsrfToken` #### Request body Required. **application/json** ```json { "$ref": "#/components/schemas/VerifyMfaRequest" } ``` #### Responses - **200**: MFA enrollment confirmed. **application/json** ```json { "$ref": "#/components/schemas/MfaConfirmationResponse" } ``` - **401**: Response - **422**: Response - **429**: Response ### POST /platform/v1/identity/mfa/challenge Operation: `challengePlatformMfa` Verify a TOTP challenge and elevate the current session. Security: ```json [ { "platformSession": [] } ] ``` #### Parameters - Reference: `#/components/parameters/CsrfToken` #### Request body Required. **application/json** ```json { "$ref": "#/components/schemas/VerifyMfaRequest" } ``` #### Responses - **200**: Response - **401**: Response - **422**: Response - **429**: Response ### POST /platform/v1/identity/mfa/recovery Operation: `recoverPlatformMfa` Consume one recovery code without satisfying sensitive step-up. Security: ```json [ { "platformSession": [] } ] ``` #### Parameters - Reference: `#/components/parameters/CsrfToken` #### Request body Required. **application/json** ```json { "$ref": "#/components/schemas/RecoverMfaRequest" } ``` #### Responses - **200**: Response - **401**: Response - **422**: Response - **429**: Response ### POST /platform/v1/identity/mfa/replacement/enroll Operation: `startPlatformMfaReplacement` Start TOTP factor replacement after fresh non-recovery step-up. Security: ```json [ { "platformSession": [] } ] ``` #### Parameters - Reference: `#/components/parameters/CsrfToken` #### Request body Required. **application/json** ```json { "$ref": "#/components/schemas/StartMfaEnrollmentRequest" } ``` #### Responses - **201**: Pending replacement factor. The active factor remains authoritative. **application/json** ```json { "$ref": "#/components/schemas/MfaEnrollmentResponse" } ``` - **401**: Response - **403**: Response - **422**: Response - **429**: Response ### POST /platform/v1/identity/mfa/replacement/confirm Operation: `confirmPlatformMfaReplacement` Atomically replace the active TOTP factor after fresh non-recovery step-up. Security: ```json [ { "platformSession": [] } ] ``` #### Parameters - Reference: `#/components/parameters/CsrfToken` #### Request body Required. **application/json** ```json { "$ref": "#/components/schemas/VerifyMfaRequest" } ``` #### Responses - **200**: Active factor replaced and new recovery codes returned once. **application/json** ```json { "$ref": "#/components/schemas/MfaConfirmationResponse" } ``` - **401**: Response - **403**: Response - **422**: Response - **429**: Response ## OAuth Tenant-bound OAuth client-credential exchange. ### POST /api/platform/v1/oauth/token Operation: `exchangePlatformClientCredential` Exchange one tenant-bound client credential for a short-lived bearer token. Security: ```json [ { "basicClient": [] } ] ``` #### Parameters - Reference: `#/components/parameters/TenantHeader` #### Request body Required. **application/json** ```json { "$ref": "#/components/schemas/OAuthTokenRequest" } ``` #### Responses - **200**: Bearer token issued. **application/json** ```json { "$ref": "#/components/schemas/OAuthTokenResponse" } ``` - **400**: Response - **401**: Response - **429**: Response - **503**: Response ## API session Authenticated machine-session inspection. ### GET /api/platform/v1/api/session Operation: `getPlatformApiSession` Verify bearer authentication, tenant binding, and the tenant:read scope. Security: ```json [ { "bearerToken": [] } ] ``` #### Parameters - Reference: `#/components/parameters/TenantHeader` #### Responses - **200**: Authenticated API session. **application/json** ```json { "$ref": "#/components/schemas/ApiSessionResponse" } ``` - **401**: Response - **403**: Response - **429**: Response ## API clients Tenant API-client lifecycle and token administration. ### GET /platform/v1/api-clients Operation: `listPlatformApiClients` List opaque API-client metadata for the current external tenant. Security: ```json [ { "platformSession": [] } ] ``` #### Parameters - Reference: `#/components/parameters/Cursor` - Reference: `#/components/parameters/Limit` #### Responses - **200**: Bounded client page. **application/json** ```json { "$ref": "#/components/schemas/ApiClientPage" } ``` - **401**: Response - **403**: Response - **422**: Response - **429**: Response ### POST /platform/v1/api-clients Operation: `createPlatformApiClient` Issue one API client and return its plaintext secret once. Security: ```json [ { "platformSession": [] } ] ``` #### Parameters - Reference: `#/components/parameters/CsrfToken` - Reference: `#/components/parameters/IdempotencyKey` #### Request body Required. **application/json** ```json { "$ref": "#/components/schemas/CreateApiClientRequest" } ``` #### Responses - **201**: Response - **401**: Response - **403**: Response - **409**: Response - **422**: Response - **429**: Response ### PATCH /platform/v1/api-clients/{client} Operation: `updatePlatformApiClient` Change a client name and expiry authority. Security: ```json [ { "platformSession": [] } ] ``` #### Parameters - Reference: `#/components/parameters/ClientPath` - Reference: `#/components/parameters/CsrfToken` - Reference: `#/components/parameters/IdempotencyKey` #### Request body Required. **application/json** ```json { "$ref": "#/components/schemas/UpdateApiClientRequest" } ``` #### Responses - **200**: Response - **401**: Response - **403**: Response - **409**: Response - **422**: Response - **429**: Response ### DELETE /platform/v1/api-clients/{client} Operation: `revokePlatformApiClient` Terminally revoke one client and all active bearer tokens. Security: ```json [ { "platformSession": [] } ] ``` #### Parameters - Reference: `#/components/parameters/ClientPath` - Reference: `#/components/parameters/CsrfToken` - Reference: `#/components/parameters/IdempotencyKey` #### Responses - **200**: Response - **401**: Response - **403**: Response - **409**: Response - **422**: Response - **429**: Response ### GET /platform/v1/api-clients/{client}/tokens Operation: `listPlatformApiClientTokens` List opaque bearer-token metadata for one client. Security: ```json [ { "platformSession": [] } ] ``` #### Parameters - Reference: `#/components/parameters/ClientPath` - Reference: `#/components/parameters/Cursor` - Reference: `#/components/parameters/Limit` #### Responses - **200**: Bounded token page. **application/json** ```json { "$ref": "#/components/schemas/ApiTokenPage" } ``` - **401**: Response - **403**: Response - **422**: Response - **429**: Response ### DELETE /platform/v1/api-clients/{client}/tokens/{token} Operation: `revokePlatformApiClientToken` Revoke one client-bound bearer token. Security: ```json [ { "platformSession": [] } ] ``` #### Parameters - Reference: `#/components/parameters/ClientPath` - Reference: `#/components/parameters/TokenPath` - Reference: `#/components/parameters/CsrfToken` - Reference: `#/components/parameters/IdempotencyKey` #### Responses - **200**: Response - **401**: Response - **403**: Response - **409**: Response - **422**: Response - **429**: Response ### PUT /platform/v1/api-clients/{client}/scopes Operation: `replacePlatformApiClientScopes` Replace client scopes and revoke existing bearer tokens. Security: ```json [ { "platformSession": [] } ] ``` #### Parameters - Reference: `#/components/parameters/ClientPath` - Reference: `#/components/parameters/CsrfToken` - Reference: `#/components/parameters/IdempotencyKey` #### Request body Required. **application/json** ```json { "$ref": "#/components/schemas/ReplaceApiClientScopesRequest" } ``` #### Responses - **200**: Response - **401**: Response - **403**: Response - **409**: Response - **422**: Response - **429**: Response ### POST /platform/v1/api-clients/{client}/rotate Operation: `rotatePlatformApiClient` Rotate a client secret with a bounded overlap window. Security: ```json [ { "platformSession": [] } ] ``` #### Parameters - Reference: `#/components/parameters/ClientPath` - Reference: `#/components/parameters/CsrfToken` - Reference: `#/components/parameters/IdempotencyKey` #### Request body **application/json** ```json { "$ref": "#/components/schemas/RotateApiClientRequest" } ``` #### Responses - **200**: Response - **401**: Response - **403**: Response - **409**: Response - **422**: Response - **429**: Response ### POST /platform/v1/api-clients/{client}/disable Operation: `disablePlatformApiClient` Disable a client and revoke existing bearer tokens. Security: ```json [ { "platformSession": [] } ] ``` #### Parameters - Reference: `#/components/parameters/ClientPath` - Reference: `#/components/parameters/CsrfToken` - Reference: `#/components/parameters/IdempotencyKey` #### Responses - **200**: Response - **401**: Response - **403**: Response - **409**: Response - **422**: Response - **429**: Response ### POST /platform/v1/api-clients/{client}/enable Operation: `enablePlatformApiClient` Re-enable a non-expired disabled client. Security: ```json [ { "platformSession": [] } ] ``` #### Parameters - Reference: `#/components/parameters/ClientPath` - Reference: `#/components/parameters/CsrfToken` - Reference: `#/components/parameters/IdempotencyKey` #### Responses - **200**: Response - **401**: Response - **403**: Response - **409**: Response - **422**: Response - **429**: Response ## Imports Guarded royalty report intake and import workflow operations. ### POST /api/platform/v1/imports Operation: `createPlatformImport` Create one tenant-owned import and expected immutable source manifest. Security: ```json [ { "bearerToken": [] } ] ``` #### Parameters - Reference: `#/components/parameters/TenantHeader` - Reference: `#/components/parameters/IdempotencyKey` #### Request body Required. **application/json** ```json { "$ref": "#/components/schemas/CreateImportRequest" } ``` #### Responses - **200**: Response - **201**: Response - **400**: Response - **401**: Response - **403**: Response - **409**: Response - **422**: Response - **429**: Response ### GET /api/platform/v1/imports/{importRef} Operation: `getPlatformImport` Return opaque import workflow and bounded profiling evidence. Security: ```json [ { "bearerToken": [] } ] ``` #### Parameters - Reference: `#/components/parameters/ImportPath` - Reference: `#/components/parameters/TenantHeader` #### Responses - **200**: Response - **400**: Response - **401**: Response - **403**: Response - **404**: Response - **429**: Response ### POST /api/platform/v1/imports/{importRef}/upload-sessions Operation: `createPlatformImportUploadSession` Issue one short-lived tenant-bound resumable upload authority. Security: ```json [ { "bearerToken": [] } ] ``` #### Parameters - Reference: `#/components/parameters/ImportPath` - Reference: `#/components/parameters/TenantHeader` - Reference: `#/components/parameters/IdempotencyKey` #### Responses - **200**: Response - **201**: Response - **400**: Response - **401**: Response - **403**: Response - **404**: Response - **409**: Response - **422**: Response - **429**: Response ### GET /api/platform/v1/imports/{importRef}/mapping-suggestions Operation: `getPlatformImportMappingSuggestions` Return bounded mapping suggestions without machine approval authority. Security: ```json [ { "bearerToken": [] } ] ``` #### Parameters - Reference: `#/components/parameters/ImportPath` - Reference: `#/components/parameters/TenantHeader` #### Responses - **200**: Response - **400**: Response - **401**: Response - **403**: Response - **404**: Response - **409**: Response - **429**: Response ### POST /api/platform/v1/imports/{importRef}/profile Operation: `profilePlatformImport` Enqueue durable profiling from verified immutable source evidence. Security: ```json [ { "bearerToken": [] } ] ``` #### Parameters - Reference: `#/components/parameters/ImportPath` - Reference: `#/components/parameters/TenantHeader` - Reference: `#/components/parameters/IdempotencyKey` #### Request body **application/json** ```json { "$ref": "#/components/schemas/ProfileImportRequest" } ``` #### Responses - **202**: Response - **400**: Response - **401**: Response - **403**: Response - **404**: Response - **409**: Response - **422**: Response - **429**: Response ### POST /api/platform/v1/imports/{importRef}/cancel Operation: `cancelPlatformImport` Cancel an eligible active import without deleting retained evidence. Security: ```json [ { "bearerToken": [] } ] ``` #### Parameters - Reference: `#/components/parameters/ImportPath` - Reference: `#/components/parameters/TenantHeader` - Reference: `#/components/parameters/IdempotencyKey` #### Request body Required. **application/json** ```json { "$ref": "#/components/schemas/CancelImportRequest" } ``` #### Responses - **200**: Response - **400**: Response - **401**: Response - **403**: Response - **404**: Response - **409**: Response - **422**: Response - **429**: Response ## Published analytics Published tenant analytics and commercial-rate reads. ### GET /api/platform/v1/analytics/summary Operation: `getPublishedAnalyticsSummary` Return exact totals from atomically published enterprise generations. Security: ```json [ { "bearerToken": [] } ] ``` #### Parameters - Reference: `#/components/parameters/TenantHeader` - `currency` in query (defined schema, required) - `currency_basis` in query (defined schema, required) - `import` in query (defined schema) - `period_start` in query (defined schema) - `period_end` in query (defined schema) #### Responses - **200**: Response - **400**: Response - **401**: Response - **403**: Response - **409**: Response - **422**: Response - **429**: Response - **503**: Response ### GET /api/platform/v1/analytics/filter-options Operation: `listPublishedAnalyticsFilterOptions` List privacy-protected filter options across published commercial dimensions. Security: ```json [ { "bearerToken": [] } ] ``` #### Parameters - Reference: `#/components/parameters/TenantHeader` - `currency` in query (defined schema, required) - `currency_basis` in query (defined schema, required) - `basis` in query (defined schema, required) - `import` in query (defined schema) - `taxonomy` in query (defined schema) - `period_start` in query (defined schema) - `period_end` in query (defined schema) #### Responses - **200**: Response - **400**: Response - **401**: Response - **403**: Response - **409**: Response - **422**: Response - **429**: Response - **503**: Response ### GET /api/platform/v1/analytics/readiness Operation: `getPublishedAnalyticsReadiness` Return aggregate availability and freshness for published analytics generations. Security: ```json [ { "bearerToken": [] } ] ``` #### Parameters - Reference: `#/components/parameters/TenantHeader` #### Responses - **200**: Response - **400**: Response - **401**: Response - **403**: Response - **409**: Response - **429**: Response - **503**: Response ### GET /api/platform/v1/analytics/rates Operation: `listPublishedObservedRates` List privacy-thresholded generation-scoped observed CPM or per-unit rates. Security: ```json [ { "bearerToken": [] } ] ``` #### Parameters - Reference: `#/components/parameters/TenantHeader` - `currency` in query (defined schema, required) - `currency_basis` in query (defined schema, required) - `basis` in query (defined schema, required) - `dimension` in query (defined schema, required) - `import` in query (defined schema) - `taxonomy` in query (defined schema) - `state` in query (defined schema) - `key` in query (string) - `period_start` in query (defined schema) - `period_end` in query (defined schema) - `limit` in query (integer) - `cursor` in query (string) #### Responses - **200**: Response - **400**: Response - **401**: Response - **403**: Response - **409**: Response - **422**: Response - **429**: Response - **503**: Response ### GET /api/platform/v1/analytics/breakdown Operation: `listPublishedAnalyticsBreakdown` Aggregate reviewed commercial dimensions across published generations. Security: ```json [ { "bearerToken": [] } ] ``` #### Parameters - Reference: `#/components/parameters/TenantHeader` - `currency` in query (defined schema, required) - `currency_basis` in query (defined schema, required) - `basis` in query (defined schema, required) - `dimension` in query (defined schema, required) - `import` in query (defined schema) - `taxonomy` in query (defined schema) - `state` in query (defined schema) - `key` in query (string) - `period_start` in query (defined schema) - `period_end` in query (defined schema) - `limit` in query (integer) - `cursor` in query (string) #### Responses - **200**: Response - **400**: Response - **401**: Response - **403**: Response - **409**: Response - **422**: Response - **429**: Response - **503**: Response ## Exports Human and machine export lifecycle and authenticated delivery. ### GET /api/platform/v1/exports Operation: `listPlatformExports` List a bounded page of safe export lifecycle states using exports:read authority. Security: ```json [ { "bearerToken": [] } ] ``` #### Parameters - Reference: `#/components/parameters/TenantHeader` - `cursor` in query (defined schema) - `limit` in query (integer) - `export_class` in query (defined schema) - `status` in query (defined schema) - `format` in query (defined schema) #### Responses - **200**: Response - **400**: Response - **401**: Response - **403**: Response - **422**: Response - **429**: Response - **503**: Response ### POST /api/platform/v1/exports Operation: `createPlatformExport` Queue one bounded external-tenant export using exports:write authority. Artifact delivery is deliberately outside this operation and contract. Security: ```json [ { "bearerToken": [] } ] ``` #### Parameters - Reference: `#/components/parameters/TenantHeader` - Reference: `#/components/parameters/IdempotencyKey` #### Request body Required. **application/json** ```json { "$ref": "#/components/schemas/CreateExportRequest" } ``` #### Responses - **200**: Response - **201**: Response - **400**: Response - **401**: Response - **403**: Response - **409**: Response - **422**: Response - **429**: Response - **503**: Response ### GET /api/platform/v1/exports/{export} Operation: `getPlatformExport` Poll safe export lifecycle state using exports:write authority. Security: ```json [ { "bearerToken": [] } ] ``` #### Parameters - Reference: `#/components/parameters/ExportPath` - Reference: `#/components/parameters/TenantHeader` #### Responses - **200**: Response - **400**: Response - **401**: Response - **403**: Response - **404**: Response - **429**: Response - **503**: Response ### GET /api/platform/v1/exports/{export}/download Operation: `downloadPlatformExport` Download one complete ready export using exports:read authority. Range and partial-content delivery are unsupported. Security: ```json [ { "bearerToken": [] } ] ``` #### Parameters - Reference: `#/components/parameters/ExportPath` - Reference: `#/components/parameters/TenantHeader` #### Responses - **200**: Response - **400**: Response - **401**: Response - **403**: Response - **404**: Response - **409**: Response - **422**: Response - **429**: Response - **503**: Response ### POST /api/platform/v1/exports/{export}/cancel Operation: `cancelPlatformExport` Cancel an export only while it remains queued using exports:write authority. Security: ```json [ { "bearerToken": [] } ] ``` #### Parameters - Reference: `#/components/parameters/ExportPath` - Reference: `#/components/parameters/TenantHeader` - Reference: `#/components/parameters/IdempotencyKey` #### Request body Required. **application/json** ```json { "$ref": "#/components/schemas/ExportCommandRequest" } ``` #### Responses - **200**: Response - **400**: Response - **401**: Response - **403**: Response - **404**: Response - **409**: Response - **422**: Response - **429**: Response - **503**: Response ### POST /api/platform/v1/exports/{export}/revoke Operation: `revokePlatformExport` Revoke a ready export using exports:write authority without delivering its artifact. Security: ```json [ { "bearerToken": [] } ] ``` #### Parameters - Reference: `#/components/parameters/ExportPath` - Reference: `#/components/parameters/TenantHeader` - Reference: `#/components/parameters/IdempotencyKey` #### Request body Required. **application/json** ```json { "$ref": "#/components/schemas/ExportCommandRequest" } ``` #### Responses - **200**: Response - **400**: Response - **401**: Response - **403**: Response - **404**: Response - **409**: Response - **422**: Response - **429**: Response - **503**: Response ### GET /platform/v1/exports Operation: `listPlatformExportsAsHuman` List a bounded page of safe export lifecycle states as an authorized external-tenant member. Security: ```json [ { "platformSession": [] } ] ``` #### Parameters - `cursor` in query (defined schema) - `limit` in query (integer) - `export_class` in query (defined schema) - `status` in query (defined schema) - `format` in query (defined schema) #### Responses - **200**: Response - **401**: Response - **403**: Response - **422**: Response - **429**: Response - **503**: Response ### POST /platform/v1/exports Operation: `createPlatformExportAsHuman` Queue one bounded export as a recently step-up-authenticated external-tenant member. Artifact delivery is deliberately outside this operation and contract. Security: ```json [ { "platformSession": [] } ] ``` #### Parameters - Reference: `#/components/parameters/CsrfToken` - Reference: `#/components/parameters/IdempotencyKey` #### Request body Required. **application/json** ```json { "$ref": "#/components/schemas/CreateExportRequest" } ``` #### Responses - **200**: Response - **201**: Response - **401**: Response - **403**: Response - **409**: Response - **422**: Response - **429**: Response - **503**: Response ### GET /platform/v1/exports/{export} Operation: `getPlatformExportAsHuman` Poll safe export lifecycle state as an authorized external-tenant member. Security: ```json [ { "platformSession": [] } ] ``` #### Parameters - Reference: `#/components/parameters/ExportPath` #### Responses - **200**: Response - **401**: Response - **403**: Response - **404**: Response - **429**: Response - **503**: Response ### GET /platform/v1/exports/{export}/download Operation: `downloadPlatformExportAsHuman` Download one complete ready export with recent non-recovery MFA step-up. Range and partial-content delivery are unsupported. Security: ```json [ { "platformSession": [] } ] ``` #### Parameters - Reference: `#/components/parameters/ExportPath` #### Responses - **200**: Response - **401**: Response - **403**: Response - **404**: Response - **409**: Response - **422**: Response - **429**: Response - **503**: Response ### POST /platform/v1/exports/{export}/cancel Operation: `cancelPlatformExportAsHuman` Cancel a queued export as a recently step-up-authenticated external-tenant member. Security: ```json [ { "platformSession": [] } ] ``` #### Parameters - Reference: `#/components/parameters/ExportPath` - Reference: `#/components/parameters/CsrfToken` - Reference: `#/components/parameters/IdempotencyKey` #### Request body Required. **application/json** ```json { "$ref": "#/components/schemas/ExportCommandRequest" } ``` #### Responses - **200**: Response - **401**: Response - **403**: Response - **404**: Response - **409**: Response - **422**: Response - **429**: Response - **503**: Response ### POST /platform/v1/exports/{export}/revoke Operation: `revokePlatformExportAsHuman` Revoke a ready export as a recently step-up-authenticated external-tenant member. Security: ```json [ { "platformSession": [] } ] ``` #### Parameters - Reference: `#/components/parameters/ExportPath` - Reference: `#/components/parameters/CsrfToken` - Reference: `#/components/parameters/IdempotencyKey` #### Request body Required. **application/json** ```json { "$ref": "#/components/schemas/ExportCommandRequest" } ``` #### Responses - **200**: Response - **401**: Response - **403**: Response - **404**: Response - **409**: Response - **422**: Response - **429**: Response - **503**: Response ## Mapping review Human source-profile mapping evidence and decision operations. ### GET /platform/v1/imports Operation: `listPlatformMappingReviews` List bounded tenant imports awaiting human mapping review. Security: ```json [ { "platformSession": [] } ] ``` #### Parameters - Reference: `#/components/parameters/Cursor` - Reference: `#/components/parameters/Limit` #### Responses - **200**: Response - **401**: Response - **403**: Response - **422**: Response - **429**: Response ### GET /platform/v1/imports/{importRef} Operation: `getPlatformMappingReview` Return profiled source evidence for one human mapping review. Security: ```json [ { "platformSession": [] } ] ``` #### Parameters - Reference: `#/components/parameters/ImportPath` #### Responses - **200**: Response - **401**: Response - **403**: Response - **404**: Response - **409**: Response - **429**: Response ### POST /platform/v1/imports/{importRef}/mapping/preview Operation: `previewPlatformMapping` Validate and preview one declarative mapping without saving it. Security: ```json [ { "platformSession": [] } ] ``` #### Parameters - Reference: `#/components/parameters/ImportPath` - Reference: `#/components/parameters/CsrfToken` #### Request body Required. **application/json** ```json { "$ref": "#/components/schemas/MappingDefinitionRequest" } ``` #### Responses - **200**: Response - **401**: Response - **403**: Response - **404**: Response - **409**: Response - **422**: Response - **429**: Response ### POST /platform/v1/imports/{importRef}/mapping/approve Operation: `approvePlatformMapping` Approve and remember one reviewed mapping under recent MFA when maker-checker is disabled. Security: ```json [ { "platformSession": [] } ] ``` #### Parameters - Reference: `#/components/parameters/ImportPath` - Reference: `#/components/parameters/CsrfToken` - Reference: `#/components/parameters/IdempotencyKey` #### Request body Required. **application/json** ```json { "$ref": "#/components/schemas/MappingDefinitionRequest" } ``` #### Responses - **200**: Response - **401**: Response - **403**: Response - **404**: Response - **409**: Response - **422**: Response - **429**: Response ### GET /platform/v1/imports/{importRef}/mapping/proposal Operation: `getPlatformMappingProposal` Return the tenant maker-checker policy and latest immutable proposal. Security: ```json [ { "platformSession": [] } ] ``` #### Parameters - Reference: `#/components/parameters/ImportPath` #### Responses - **200**: Response - **401**: Response - **403**: Response - **404**: Response - **429**: Response ### POST /platform/v1/imports/{importRef}/mapping/proposals Operation: `proposePlatformMapping` Submit exact mapping-preview evidence for a distinct checker under recent MFA. Security: ```json [ { "platformSession": [] } ] ``` #### Parameters - Reference: `#/components/parameters/ImportPath` - Reference: `#/components/parameters/CsrfToken` - Reference: `#/components/parameters/IdempotencyKey` #### Request body Required. **application/json** ```json { "$ref": "#/components/schemas/MappingDefinitionRequest" } ``` #### Responses - **201**: Response - **401**: Response - **403**: Response - **404**: Response - **409**: Response - **422**: Response - **429**: Response ### POST /platform/v1/mapping-proposals/{proposalRef}/approve Operation: `approvePlatformMappingProposal` Approve an exact proposal as a distinct checker under recent MFA. Security: ```json [ { "platformSession": [] } ] ``` #### Parameters - Reference: `#/components/parameters/MappingProposalPath` - Reference: `#/components/parameters/CsrfToken` - Reference: `#/components/parameters/IdempotencyKey` #### Responses - **200**: Response - **401**: Response - **403**: Response - **404**: Response - **409**: Response - **422**: Response - **429**: Response ### POST /platform/v1/mapping-proposals/{proposalRef}/reject Operation: `rejectPlatformMappingProposal` Reject an exact proposal as a distinct checker under recent MFA. Security: ```json [ { "platformSession": [] } ] ``` #### Parameters - Reference: `#/components/parameters/MappingProposalPath` - Reference: `#/components/parameters/CsrfToken` - Reference: `#/components/parameters/IdempotencyKey` #### Request body Required. **application/json** ```json { "$ref": "#/components/schemas/RejectMappingProposalRequest" } ``` #### Responses - **200**: Response - **401**: Response - **403**: Response - **404**: Response - **409**: Response - **422**: Response - **429**: Response ## Reconciliation Completed import and cross-domain reconciliation evidence. ### GET /platform/v1/reconciliations Operation: `listPlatformReconciliations` List bounded completed canonical reconciliations with validation evidence. Security: ```json [ { "platformSession": [] } ] ``` #### Parameters - Reference: `#/components/parameters/Cursor` - Reference: `#/components/parameters/Limit` #### Responses - **200**: Response - **401**: Response - **403**: Response - **409**: Response - **422**: Response - **429**: Response ### GET /platform/v1/reconciliations/{importRef} Operation: `getPlatformReconciliation` Return exact complete-file canonical and validation evidence for one import. Security: ```json [ { "platformSession": [] } ] ``` #### Parameters - Reference: `#/components/parameters/ImportPath` #### Responses - **200**: Response - **401**: Response - **403**: Response - **404**: Response - **409**: Response - **429**: Response ## Catalog review Human catalog-match evidence and decision operations. ### GET /platform/v1/catalog/entities Operation: `listPlatformCatalogEntities` List tenant-scoped catalog entities with their latest verified snapshots. Security: ```json [ { "platformSession": [] } ] ``` #### Parameters - Reference: `#/components/parameters/Cursor` - Reference: `#/components/parameters/Limit` - `entity_type` in query (string) #### Responses - **200**: Bounded catalog entity page. **application/json** ```json { "$ref": "#/components/schemas/CatalogEntityPage" } ``` - **401**: Response - **403**: Response - **422**: Response - **429**: Response ### GET /platform/v1/catalog/entities/{entity} Operation: `getPlatformCatalogEntity` Return one tenant-owned catalog entity with its latest verified snapshot and identifiers. Security: ```json [ { "platformSession": [] } ] ``` #### Parameters - `entity` in path (defined schema, required) #### Responses - **200**: Verified catalog entity detail. **application/json** ```json { "$ref": "#/components/schemas/CatalogEntityDetailResponse" } ``` - **401**: Response - **403**: Response - **404**: Response - **422**: Response - **429**: Response ### GET /platform/v1/catalog/matches Operation: `listPlatformCatalogMatches` List tenant-scoped catalog match cases for authorized human review. Security: ```json [ { "platformSession": [] } ] ``` #### Parameters - Reference: `#/components/parameters/Cursor` - Reference: `#/components/parameters/Limit` - Reference: `#/components/parameters/CatalogReviewState` #### Responses - **200**: Bounded catalog match page. **application/json** ```json { "$ref": "#/components/schemas/CatalogReviewPage" } ``` - **401**: Response - **403**: Response - **422**: Response - **429**: Response ### GET /platform/v1/catalog/matches/metrics Operation: `getPlatformCatalogMatchMetrics` Return tenant-scoped review queue and accounting-suspense metrics. Security: ```json [ { "platformSession": [] } ] ``` #### Responses - **200**: Current queue, candidate and suspense counts. **application/json** ```json { "$ref": "#/components/schemas/CatalogReviewMetricsResponse" } ``` - **401**: Response - **403**: Response - **429**: Response ### POST /platform/v1/catalog/matches/decisions/bulk-exact Operation: `bulkApproveExactPlatformCatalogMatches` Approve at most twenty exact catalog candidates with fresh MFA and one idempotent transaction. Security: ```json [ { "platformSession": [] } ] ``` #### Parameters - Reference: `#/components/parameters/CsrfToken` - Reference: `#/components/parameters/IdempotencyKey` #### Request body Required. **application/json** ```json { "$ref": "#/components/schemas/CatalogBulkExactDecisionRequest" } ``` #### Responses - **200**: Exact catalog decisions completed atomically or replayed. **application/json** ```json { "$ref": "#/components/schemas/CatalogBulkExactDecisionResponse" } ``` - **401**: Response - **403**: Response - **409**: Response - **422**: Response - **429**: Response ### GET /platform/v1/catalog/matches/{case} Operation: `getPlatformCatalogMatch` Return one opaque catalog match case and its latest reviewed state. Security: ```json [ { "platformSession": [] } ] ``` #### Parameters - Reference: `#/components/parameters/CasePath` #### Responses - **200**: Catalog match evidence. **application/json** ```json { "$ref": "#/components/schemas/CatalogMatchDetailResponse" } ``` - **401**: Response - **403**: Response - **404**: Response - **422**: Response - **429**: Response ### GET /platform/v1/catalog/matches/{case}/candidates Operation: `listPlatformCatalogMatchCandidates` List verified candidate snapshots for one catalog match case. Security: ```json [ { "platformSession": [] } ] ``` #### Parameters - Reference: `#/components/parameters/CasePath` - Reference: `#/components/parameters/Cursor` - Reference: `#/components/parameters/Limit` #### Responses - **200**: Bounded verified candidate page. **application/json** ```json { "$ref": "#/components/schemas/CatalogCandidatePage" } ``` - **401**: Response - **403**: Response - **404**: Response - **422**: Response - **429**: Response ### POST /platform/v1/catalog/matches/{case}/disputes Operation: `linkPlatformCatalogMatchDispute` Link one existing tenant dispute to a catalog match case as immutable suspense evidence. Security: ```json [ { "platformSession": [] } ] ``` #### Parameters - Reference: `#/components/parameters/CasePath` - Reference: `#/components/parameters/CsrfToken` - Reference: `#/components/parameters/IdempotencyKey` #### Request body Required. **application/json** ```json { "$ref": "#/components/schemas/CatalogDisputeLinkRequest" } ``` #### Responses - **200**: Dispute link completed or replayed. **application/json** ```json { "$ref": "#/components/schemas/CatalogDisputeLinkResponse" } ``` - **401**: Response - **403**: Response - **409**: Response - **422**: Response - **429**: Response ### POST /platform/v1/catalog/matches/{case}/decision Operation: `decidePlatformCatalogMatch` Approve, reject, or hold one match with fresh MFA and idempotency. Security: ```json [ { "platformSession": [] } ] ``` #### Parameters - Reference: `#/components/parameters/CasePath` - Reference: `#/components/parameters/CsrfToken` - Reference: `#/components/parameters/IdempotencyKey` #### Request body Required. **application/json** ```json { "$ref": "#/components/schemas/CatalogDecisionRequest" } ``` #### Responses - **200**: Catalog decision completed or replayed. **application/json** ```json { "$ref": "#/components/schemas/CatalogDecisionResponse" } ``` - **401**: Response - **403**: Response - **409**: Response - **422**: Response - **429**: Response ## Anomalies Human anomaly inventory and immutable investigation comments. ### GET /platform/v1/anomalies/cases Operation: `listPlatformAnomalyCases` List bounded tenant-scoped anomaly cases for authorized operators. Security: ```json [ { "platformSession": [] } ] ``` #### Parameters - Reference: `#/components/parameters/Cursor` - Reference: `#/components/parameters/Limit` - `status` in query (defined schema) - `hold_status` in query (defined schema) - `class` in query (defined schema) - `severity` in query (defined schema) - `consequence` in query (defined schema) - `assigned_to` in query (defined schema) #### Responses - **200**: Bounded anomaly case page. **application/json** ```json { "$ref": "#/components/schemas/AnomalyCasePage" } ``` - **401**: Response - **403**: Response - **422**: Response - **429**: Response ### GET /platform/v1/anomalies/cases/{case} Operation: `getPlatformAnomalyCase` Return one tenant anomaly case with its immutable comment timeline. Security: ```json [ { "platformSession": [] } ] ``` #### Parameters - Reference: `#/components/parameters/CasePath` #### Responses - **200**: Verified anomaly case detail. **application/json** ```json { "$ref": "#/components/schemas/AnomalyCaseDetailResponse" } ``` - **401**: Response - **403**: Response - **404**: Response - **429**: Response ### GET /platform/v1/anomalies/cases/metrics Operation: `getPlatformAnomalyMetrics` Return tenant anomaly queue and suppression-expiry metrics. Security: ```json [ { "platformSession": [] } ] ``` #### Responses - **200**: Current tenant anomaly metrics. **application/json** ```json { "$ref": "#/components/schemas/AnomalyMetricsResponse" } ``` - **401**: Response - **403**: Response - **429**: Response ### POST /platform/v1/anomalies/cases/{case}/comments Operation: `commentPlatformAnomalyCase` Append one idempotent retained comment to a tenant anomaly case. Security: ```json [ { "platformSession": [] } ] ``` #### Parameters - Reference: `#/components/parameters/CasePath` - Reference: `#/components/parameters/CsrfToken` - Reference: `#/components/parameters/IdempotencyKey` #### Request body Required. **application/json** ```json { "$ref": "#/components/schemas/AnomalyCommentRequest" } ``` #### Responses - **201**: Immutable anomaly comment created or replayed. **application/json** ```json { "$ref": "#/components/schemas/AnomalyCommentResponse" } ``` - **401**: Response - **403**: Response - **422**: Response - **429**: Response ## Disputes Dispute evidence, workflow, communications, and accounting commands. ### GET /platform/v1/disputes Operation: `listPlatformDisputes` List tenant-scoped dispute summaries for approved external finance readers. Security: ```json [ { "platformSession": [] } ] ``` #### Parameters - Reference: `#/components/parameters/Cursor` - Reference: `#/components/parameters/Limit` - Reference: `#/components/parameters/DisputeState` #### Responses - **200**: Bounded opaque dispute page. **application/json** ```json { "$ref": "#/components/schemas/DisputePage" } ``` - **401**: Response - **403**: Response - **422**: Response - **429**: Response - **503**: Response ### POST /platform/v1/disputes Operation: `submitPlatformDispute` Submit one verified-evidence statement dispute and post its capped suspense hold. Security: ```json [ { "platformSession": [] } ] ``` #### Parameters - Reference: `#/components/parameters/CsrfToken` - Reference: `#/components/parameters/IdempotencyKey` #### Request body Required. **application/json** ```json { "$ref": "#/components/schemas/SubmitDisputeRequest" } ``` #### Responses - **201**: Dispute and suspense hold created or replayed. **application/json** ```json { "$ref": "#/components/schemas/SubmittedDisputeResponse" } ``` - **401**: Response - **403**: Response - **409**: Response - **422**: Response - **429**: Response - **503**: Response ### POST /platform/v1/disputes/evidence-manifests Operation: `uploadPlatformDisputeEvidence` Verify, malware-scan, immutably store, and approve one dispute evidence item. Security: ```json [ { "platformSession": [] } ] ``` #### Parameters - Reference: `#/components/parameters/CsrfToken` - Reference: `#/components/parameters/IdempotencyKey` #### Request body Required. **multipart/form-data** ```json { "$ref": "#/components/schemas/UploadDisputeEvidenceRequest" } ``` #### Responses - **201**: Byte-verified clean evidence manifest created or exactly replayed. **application/json** ```json { "$ref": "#/components/schemas/UploadedDisputeEvidenceResponse" } ``` - **401**: Response - **403**: Response - **409**: Response - **422**: Response - **429**: Response - **503**: Response ### GET /platform/v1/disputes/{dispute} Operation: `getPlatformDispute` Return verified immutable dispute, event, outcome, and evidence metadata. Security: ```json [ { "platformSession": [] } ] ``` #### Parameters - Reference: `#/components/parameters/DisputePath` #### Responses - **200**: Opaque dispute detail without storage keys or evidence digests. **application/json** ```json { "$ref": "#/components/schemas/DisputeDetailResponse" } ``` - **401**: Response - **403**: Response - **404**: Response - **422**: Response - **429**: Response - **503**: Response ### POST /platform/v1/disputes/{dispute}/acknowledge Operation: `acknowledgePlatformDispute` Acknowledge one open dispute with distinct-actor and idempotency controls. Security: ```json [ { "platformSession": [] } ] ``` #### Parameters - Reference: `#/components/parameters/DisputePath` - Reference: `#/components/parameters/CsrfToken` - Reference: `#/components/parameters/IdempotencyKey` #### Request body Required. **application/json** ```json { "$ref": "#/components/schemas/AcknowledgeDisputeRequest" } ``` #### Responses - **200**: Dispute acknowledgement created or replayed. **application/json** ```json { "$ref": "#/components/schemas/AcknowledgedDisputeResponse" } ``` - **401**: Response - **403**: Response - **409**: Response - **422**: Response - **429**: Response - **503**: Response ### POST /platform/v1/disputes/{dispute}/assign Operation: `assignPlatformDispute` Assign or reassign one acknowledged open dispute to an approved tenant finance user. Security: ```json [ { "platformSession": [] } ] ``` #### Parameters - Reference: `#/components/parameters/DisputePath` - Reference: `#/components/parameters/CsrfToken` - Reference: `#/components/parameters/IdempotencyKey` #### Request body Required. **application/json** ```json { "$ref": "#/components/schemas/AssignDisputeRequest" } ``` #### Responses - **200**: Dispute assignment created or replayed. **application/json** ```json { "$ref": "#/components/schemas/AssignedDisputeResponse" } ``` - **401**: Response - **403**: Response - **409**: Response - **422**: Response - **429**: Response - **503**: Response ### POST /platform/v1/disputes/{dispute}/escalate Operation: `escalatePlatformDispute` Escalate one proposed resolution to a strictly higher tenant finance role. Security: ```json [ { "platformSession": [] } ] ``` #### Parameters - Reference: `#/components/parameters/DisputePath` - Reference: `#/components/parameters/CsrfToken` - Reference: `#/components/parameters/IdempotencyKey` #### Request body Required. **application/json** ```json { "$ref": "#/components/schemas/EscalateDisputeRequest" } ``` #### Responses - **200**: Dispute escalation created or replayed. **application/json** ```json { "$ref": "#/components/schemas/EscalatedDisputeResponse" } ``` - **401**: Response - **403**: Response - **409**: Response - **422**: Response - **429**: Response - **503**: Response ### GET /platform/v1/disputes/{dispute}/notes Operation: `listPlatformDisputeNotes` List one bounded page of immutable internal dispute notes. Security: ```json [ { "platformSession": [] } ] ``` #### Parameters - Reference: `#/components/parameters/DisputePath` - Reference: `#/components/parameters/Cursor` - Reference: `#/components/parameters/Limit` #### Responses - **200**: Opaque internal note page. **application/json** ```json { "$ref": "#/components/schemas/DisputeNotePage" } ``` - **401**: Response - **403**: Response - **404**: Response - **422**: Response - **429**: Response - **503**: Response ### POST /platform/v1/disputes/{dispute}/notes Operation: `recordPlatformDisputeNote` Append one immutable internal-only dispute note. Security: ```json [ { "platformSession": [] } ] ``` #### Parameters - Reference: `#/components/parameters/DisputePath` - Reference: `#/components/parameters/CsrfToken` - Reference: `#/components/parameters/IdempotencyKey` #### Request body Required. **application/json** ```json { "$ref": "#/components/schemas/RecordDisputeNoteRequest" } ``` #### Responses - **201**: Internal dispute note recorded or replayed. **application/json** ```json { "$ref": "#/components/schemas/RecordedDisputeNoteResponse" } ``` - **401**: Response - **403**: Response - **409**: Response - **422**: Response - **429**: Response - **503**: Response ### POST /platform/v1/disputes/{dispute}/communications Operation: `recordPlatformDisputeCommunication` Append one immutable inbound or outbound external communication under recent MFA. Security: ```json [ { "platformSession": [] } ] ``` #### Parameters - Reference: `#/components/parameters/DisputePath` - Reference: `#/components/parameters/CsrfToken` - Reference: `#/components/parameters/IdempotencyKey` #### Request body Required. **application/json** ```json { "$ref": "#/components/schemas/RecordDisputeCommunicationRequest" } ``` #### Responses - **201**: External communication evidence recorded or exactly replayed. **application/json** ```json { "$ref": "#/components/schemas/RecordedDisputeCommunicationResponse" } ``` - **401**: Response - **403**: Response - **409**: Response - **422**: Response - **429**: Response - **503**: Response ### POST /platform/v1/disputes/{dispute}/evidence/{item}/access Operation: `grantPlatformDisputeEvidenceAccess` Grant one short-lived signed and actor-bound evidence download. Security: ```json [ { "platformSession": [] } ] ``` #### Parameters - Reference: `#/components/parameters/DisputePath` - Reference: `#/components/parameters/EvidenceItemPath` - Reference: `#/components/parameters/CsrfToken` - Reference: `#/components/parameters/IdempotencyKey` #### Responses - **201**: Evidence access created or replayed. **application/json** ```json { "$ref": "#/components/schemas/GrantedDisputeEvidenceAccessResponse" } ``` - **401**: Response - **403**: Response - **404**: Response - **409**: Response - **422**: Response - **429**: Response - **503**: Response ### GET /platform/v1/disputes/{dispute}/evidence/{item}/downloads/{access} Operation: `downloadPlatformDisputeEvidence` Consume one signed evidence access after immutable object verification. Security: ```json [ { "platformSession": [] } ] ``` #### Parameters - Reference: `#/components/parameters/DisputePath` - Reference: `#/components/parameters/EvidenceItemPath` - Reference: `#/components/parameters/EvidenceAccessPath` - `expires` in query (integer, required) - `signature` in query (string, required) #### Responses - **200**: Verified evidence bytes. **application/octet-stream** ```json { "type": "string", "format": "binary" } ``` - **401**: Response - **403**: Response - **404**: Response - **409**: Response - **422**: Response - **429**: Response - **503**: Response ### POST /platform/v1/disputes/{dispute}/propose Operation: `proposePlatformDisputeResolution` Propose one immutable outcome as the current assignee after investigation. Security: ```json [ { "platformSession": [] } ] ``` #### Parameters - Reference: `#/components/parameters/DisputePath` - Reference: `#/components/parameters/CsrfToken` - Reference: `#/components/parameters/IdempotencyKey` #### Request body Required. **application/json** ```json { "$ref": "#/components/schemas/ProposeDisputeRequest" } ``` #### Responses - **200**: Proposed resolution created or replayed. **application/json** ```json { "$ref": "#/components/schemas/ProposedDisputeResponse" } ``` - **401**: Response - **403**: Response - **409**: Response - **422**: Response - **429**: Response - **503**: Response ### POST /platform/v1/disputes/{dispute}/release Operation: `releasePlatformDispute` Reject or approve withdrawal through an exact maker-checker hold reversal. Security: ```json [ { "platformSession": [] } ] ``` #### Parameters - Reference: `#/components/parameters/DisputePath` - Reference: `#/components/parameters/CsrfToken` - Reference: `#/components/parameters/IdempotencyKey` #### Request body Required. **application/json** ```json { "$ref": "#/components/schemas/ReleaseDisputeRequest" } ``` #### Responses - **200**: Dispute hold released or replayed. **application/json** ```json { "$ref": "#/components/schemas/ReleasedDisputeResponse" } ``` - **401**: Response - **403**: Response - **409**: Response - **422**: Response - **429**: Response - **503**: Response ### POST /platform/v1/disputes/{dispute}/reopen Operation: `reopenPlatformDispute` Create one fresh child dispute from an immutable rejected, withdrawn or upheld case. Security: ```json [ { "platformSession": [] } ] ``` #### Parameters - Reference: `#/components/parameters/DisputePath` - Reference: `#/components/parameters/CsrfToken` - Reference: `#/components/parameters/IdempotencyKey` #### Request body Required. **application/json** ```json { "$ref": "#/components/schemas/ReopenDisputeRequest" } ``` #### Responses - **201**: Reopened child dispute created or exactly replayed. **application/json** ```json { "$ref": "#/components/schemas/ReopenedDisputeResponse" } ``` - **401**: Response - **403**: Response - **409**: Response - **422**: Response - **429**: Response - **503**: Response ### POST /platform/v1/disputes/{dispute}/investigate Operation: `investigatePlatformDispute` Start one immutable investigation as the current verified dispute assignee. Security: ```json [ { "platformSession": [] } ] ``` #### Parameters - Reference: `#/components/parameters/DisputePath` - Reference: `#/components/parameters/CsrfToken` - Reference: `#/components/parameters/IdempotencyKey` #### Request body Required. **application/json** ```json { "$ref": "#/components/schemas/InvestigateDisputeRequest" } ``` #### Responses - **200**: Dispute investigation created or replayed. **application/json** ```json { "$ref": "#/components/schemas/InvestigatingDisputeResponse" } ``` - **401**: Response - **403**: Response - **409**: Response - **422**: Response - **429**: Response - **503**: Response ### POST /platform/v1/disputes/{dispute}/uphold Operation: `upholdPlatformDispute` Uphold only after complete published correction and replacement evidence. Security: ```json [ { "platformSession": [] } ] ``` #### Parameters - Reference: `#/components/parameters/DisputePath` - Reference: `#/components/parameters/CsrfToken` - Reference: `#/components/parameters/IdempotencyKey` #### Request body Required. **application/json** ```json { "$ref": "#/components/schemas/UpholdDisputeRequest" } ``` #### Responses - **200**: Correction-bound uphold completed or replayed. **application/json** ```json { "$ref": "#/components/schemas/UpheldDisputeResponse" } ``` - **401**: Response - **403**: Response - **409**: Response - **422**: Response - **429**: Response - **503**: Response ## Payout operations Payout exception and protected alert-route operations. ### GET /platform/v1/payout-exceptions Operation: `listPlatformPayoutExceptions` List bounded secret-safe payout ambiguity and dead-letter cases for external finance readers. Security: ```json [ { "platformSession": [] } ] ``` #### Parameters - Reference: `#/components/parameters/Cursor` - Reference: `#/components/parameters/Limit` - Reference: `#/components/parameters/PayoutExceptionState` #### Responses - **200**: Opaque payout exception page without destinations, provider references, signatures, or financial values. **application/json** ```json { "$ref": "#/components/schemas/PayoutExceptionPage" } ``` - **401**: Response - **403**: Response - **422**: Response - **429**: Response - **503**: Response ### GET /platform/v1/payout-exceptions/{case} Operation: `getPlatformPayoutException` Return one verified payout exception and its immutable investigation history. Security: ```json [ { "platformSession": [] } ] ``` #### Parameters - Reference: `#/components/parameters/PayoutExceptionPath` #### Responses - **200**: Secret-safe payout exception detail. **application/json** ```json { "$ref": "#/components/schemas/PayoutExceptionDetailResponse" } ``` - **401**: Response - **403**: Response - **404**: Response - **429**: Response - **503**: Response ### POST /platform/v1/payout-exceptions/{case}/investigations Operation: `investigatePlatformPayoutException` Append an immutable finding without changing payout or queue state. Security: ```json [ { "platformSession": [] } ] ``` #### Parameters - Reference: `#/components/parameters/PayoutExceptionPath` - Reference: `#/components/parameters/CsrfToken` - Reference: `#/components/parameters/IdempotencyKey` #### Request body Required. **application/json** ```json { "$ref": "#/components/schemas/InvestigatePayoutExceptionRequest" } ``` #### Responses - **201**: Investigation recorded or exactly replayed. **application/json** ```json { "$ref": "#/components/schemas/PayoutExceptionEventResponse" } ``` - **401**: Response - **403**: Response - **409**: Response - **422**: Response - **429**: Response - **503**: Response ### POST /platform/v1/payout-exceptions/{case}/lookup-rechecks Operation: `requestPlatformPayoutLookupRecheck` Make a recoverable ambiguity due for provider lookup after a distinct checker approves. This command never submits or resubmits a payout and is unavailable for dead letters. Security: ```json [ { "platformSession": [] } ] ``` #### Parameters - Reference: `#/components/parameters/PayoutExceptionPath` - Reference: `#/components/parameters/CsrfToken` - Reference: `#/components/parameters/IdempotencyKey` #### Request body Required. **application/json** ```json { "$ref": "#/components/schemas/RecheckPayoutExceptionRequest" } ``` #### Responses - **200**: Lookup-only recheck recorded and made due, or exactly replayed. **application/json** ```json { "$ref": "#/components/schemas/PayoutLookupRecheckResponse" } ``` - **401**: Response - **403**: Response - **409**: Response - **422**: Response - **429**: Response - **503**: Response ### GET /platform/v1/payout-alert-routes Operation: `listPlatformPayoutAlertRoutes` List reviewed tenant alert routes without addresses, credentials, hashes, or internal identifiers. Security: ```json [ { "platformSession": [] } ] ``` #### Parameters - Reference: `#/components/parameters/Cursor` - Reference: `#/components/parameters/Limit` - Reference: `#/components/parameters/PayoutAlertRouteStatus` #### Responses - **200**: Bounded opaque route-authority page. **application/json** ```json { "$ref": "#/components/schemas/PayoutAlertRoutePage" } ``` - **401**: Response - **403**: Response - **422**: Response - **429**: Response - **503**: Response ### GET /platform/v1/payout-alert-routes/{route} Operation: `getPlatformPayoutAlertRoute` Return one verified opaque payout-alert route authority. Security: ```json [ { "platformSession": [] } ] ``` #### Parameters - Reference: `#/components/parameters/PayoutAlertRoutePath` #### Responses - **200**: Verified route authority. **application/json** ```json { "$ref": "#/components/schemas/PayoutAlertRouteResponse" } ``` - **401**: Response - **403**: Response - **404**: Response - **429**: Response - **503**: Response ### POST /platform/v1/payout-alert-routes/{route}/retire Operation: `retirePlatformPayoutAlertRoute` Retire a route with recent MFA and an actor distinct from its proposer. Security: ```json [ { "platformSession": [] } ] ``` #### Parameters - Reference: `#/components/parameters/PayoutAlertRoutePath` - Reference: `#/components/parameters/CsrfToken` - Reference: `#/components/parameters/IdempotencyKey` #### Responses - **200**: Route retired or exactly replayed. **application/json** ```json { "$ref": "#/components/schemas/PayoutAlertRouteResponse" } ``` - **401**: Response - **403**: Response - **409**: Response - **422**: Response - **429**: Response - **503**: Response ### GET /platform/v1/payout-alert-route-proposals Operation: `listPlatformPayoutAlertRouteProposals` List retained maker-checker route proposals for external finance readers. Security: ```json [ { "platformSession": [] } ] ``` #### Parameters - Reference: `#/components/parameters/Cursor` - Reference: `#/components/parameters/Limit` - Reference: `#/components/parameters/PayoutAlertRouteProposalStatus` #### Responses - **200**: Bounded verified proposal page. **application/json** ```json { "$ref": "#/components/schemas/PayoutAlertRouteProposalPage" } ``` - **401**: Response - **403**: Response - **422**: Response - **429**: Response - **503**: Response ### POST /platform/v1/payout-alert-route-proposals Operation: `proposePlatformPayoutAlertRoute` Propose opaque route authority without creating an active delivery route. Security: ```json [ { "platformSession": [] } ] ``` #### Parameters - Reference: `#/components/parameters/CsrfToken` - Reference: `#/components/parameters/IdempotencyKey` #### Request body Required. **application/json** ```json { "$ref": "#/components/schemas/ProposePayoutAlertRouteRequest" } ``` #### Responses - **201**: Proposal created or exactly replayed. **application/json** ```json { "$ref": "#/components/schemas/PayoutAlertRouteProposalCommandResponse" } ``` - **401**: Response - **403**: Response - **409**: Response - **422**: Response - **429**: Response - **503**: Response ### GET /platform/v1/payout-alert-route-proposals/{proposal} Operation: `getPlatformPayoutAlertRouteProposal` Return one verified retained payout-alert route proposal. Security: ```json [ { "platformSession": [] } ] ``` #### Parameters - Reference: `#/components/parameters/PayoutAlertRouteProposalPath` #### Responses - **200**: Verified proposal authority. **application/json** ```json { "$ref": "#/components/schemas/PayoutAlertRouteProposalResponse" } ``` - **401**: Response - **403**: Response - **404**: Response - **429**: Response - **503**: Response ### POST /platform/v1/payout-alert-route-proposals/{proposal}/approve Operation: `approvePlatformPayoutAlertRouteProposal` Create route authority after a distinct finance identity approves with recent MFA. Security: ```json [ { "platformSession": [] } ] ``` #### Parameters - Reference: `#/components/parameters/PayoutAlertRouteProposalPath` - Reference: `#/components/parameters/CsrfToken` - Reference: `#/components/parameters/IdempotencyKey` #### Responses - **200**: Proposal approved and route created, or exactly replayed. **application/json** ```json { "$ref": "#/components/schemas/PayoutAlertRouteApprovalResponse" } ``` - **401**: Response - **403**: Response - **409**: Response - **422**: Response - **429**: Response - **503**: Response ### POST /platform/v1/payout-alert-route-proposals/{proposal}/reject Operation: `rejectPlatformPayoutAlertRouteProposal` Reject route authority without creating a delivery route. Security: ```json [ { "platformSession": [] } ] ``` #### Parameters - Reference: `#/components/parameters/PayoutAlertRouteProposalPath` - Reference: `#/components/parameters/CsrfToken` - Reference: `#/components/parameters/IdempotencyKey` #### Request body Required. **application/json** ```json { "$ref": "#/components/schemas/RejectPayoutAlertRouteProposalRequest" } ``` #### Responses - **200**: Proposal rejected or exactly replayed. **application/json** ```json { "$ref": "#/components/schemas/PayoutAlertRouteProposalCommandResponse" } ``` - **401**: Response - **403**: Response - **409**: Response - **422**: Response - **429**: Response - **503**: Response ## Webhook ingress Partner-authenticated tenant webhook intake with ordered replay protection. ### POST /api/platform/v1/webhooks/inbound/{tenant}/{endpoint} Operation: `acceptPlatformInboundWebhook` Accept one bounded, signed and ordered partner event. The guarded route is absent unless generic inbound webhooks and its HTTP boundary are enabled. Security: ```json [] ``` #### Parameters - `tenant` in path (defined schema, required): Opaque external tenant reference bound into endpoint authority. - `endpoint` in path (defined schema, required): Opaque webhook endpoint reference. - `X-Webhook-Key-Id` in header (string, required): Endpoint key generation identifier. - `X-Webhook-Timestamp` in header (defined schema, required): Signed event timestamp within the accepted skew window. - `X-Webhook-Nonce` in header (defined schema, required): Unique signed request nonce. - `X-Webhook-Sequence` in header (integer, required): Strictly increasing endpoint sequence number. - `X-Webhook-Event` in header (string, required): Stable partner event reference used for exact replay. - `X-Webhook-Schema` in header (string, required): Endpoint-bound payload schema version. - `X-Webhook-Signature` in header (string, required): Lowercase hexadecimal HMAC-SHA256 over the canonical signed envelope. #### Request body Required. **application/json** ```json { "$ref": "#/components/schemas/WebhookIngressPayload" } ``` #### Responses - **202**: Event accepted or exactly replayed. **application/json** ```json { "$ref": "#/components/schemas/WebhookIngressResponse" } ``` - **401**: Response - **413**: Response - **415**: Response - **429**: Response - **503**: Response ## Component schemas ```json { "Uuid": { "type": "string", "format": "uuid" }, "NullableUuid": { "type": [ "string", "null" ], "format": "uuid" }, "IsoDateTime": { "type": "string", "format": "date-time" }, "NullableIsoDateTime": { "type": [ "string", "null" ], "format": "date-time" }, "CurrencyCode": { "type": "string", "pattern": "^[A-Z]{3}$" }, "CurrencyBasis": { "type": "string", "enum": [ "reported", "settlement" ] }, "RateBasis": { "type": "string", "enum": [ "streams", "units" ] }, "ReportMonth": { "type": "string", "format": "date", "pattern": "^\\d{4}-\\d{2}-01$" }, "CommercialDimension": { "type": "string", "enum": [ "dsp", "territory", "service_tier", "subscription_plan", "subscriber_type", "commercial_model", "use_type", "offer", "device", "quality", "channel" ] }, "CommercialValueState": { "type": "string", "enum": [ "mapped", "unknown", "not_supplied", "not_applicable", "invalid" ] }, "Scope": { "type": "string", "enum": [ "analytics:read", "calculations:read", "calculations:write", "catalog:read", "catalog:write", "exports:read", "exports:write", "imports:read", "imports:write", "ledger:read", "payees:read", "payees:write", "statements:read", "tenant:read", "webhooks:read", "webhooks:write" ] }, "ExportClass": { "type": "string", "enum": [ "dashboard_extract", "canonical_detail", "rejected_rows", "allocation_detail", "statement", "ledger_reconciliation", "audit_evidence" ] }, "ExportFormat": { "type": "string", "enum": [ "csv", "json", "parquet", "pdf", "zip" ] }, "ExportStatus": { "type": "string", "enum": [ "queued", "generating", "validating", "ready", "failed", "cancelled", "expired", "revoked" ] }, "ExportReportingPeriod": { "type": "object", "additionalProperties": false, "required": [ "from", "to" ], "properties": { "from": { "type": "string", "format": "date" }, "to": { "type": "string", "format": "date" } } }, "ExportFilterValue": { "oneOf": [ { "type": "string", "minLength": 1, "maxLength": 200 }, { "type": "array", "minItems": 1, "maxItems": 100, "items": { "type": "string", "minLength": 1, "maxLength": 200 } } ] }, "ExportSpecification": { "type": "object", "additionalProperties": false, "required": [ "currency_basis", "filters", "locale", "max_bytes", "payee_ref", "reporting_period", "schema_version", "source_ref", "source_type", "timezone" ], "properties": { "currency_basis": { "type": [ "string", "null" ], "enum": [ "reported", "settlement", "tenant_reporting", null ] }, "filters": { "type": "object", "maxProperties": 50, "propertyNames": { "type": "string", "pattern": "^[a-z][a-z0-9_]{0,63}$" }, "additionalProperties": { "$ref": "#/components/schemas/ExportFilterValue" } }, "locale": { "type": "string", "pattern": "^[a-z]{2,3}(?:-[A-Z]{2})?$" }, "max_bytes": { "type": "integer", "minimum": 1, "maximum": 53687091200 }, "payee_ref": { "$ref": "#/components/schemas/NullableUuid" }, "reporting_period": { "$ref": "#/components/schemas/ExportReportingPeriod" }, "schema_version": { "type": "string", "minLength": 1, "maxLength": 40, "pattern": "^[A-Za-z0-9][A-Za-z0-9._-]*$" }, "source_ref": { "$ref": "#/components/schemas/Uuid" }, "source_type": { "type": "string", "enum": [ "analytics_generation", "canonical_manifest", "calculation_run", "statement", "ledger_period", "audit_window" ] }, "timezone": { "type": "string", "minLength": 1, "maxLength": 80 } } }, "CreateExportRequest": { "type": "object", "additionalProperties": false, "required": [ "export_class", "format", "specification" ], "allOf": [ { "if": { "required": [ "export_class", "format" ], "properties": { "export_class": { "const": "ledger_reconciliation" }, "format": { "const": "json" } } }, "then": { "properties": { "specification": { "allOf": [ { "$ref": "#/components/schemas/ExportSpecification" }, { "type": "object", "properties": { "currency_basis": { "type": [ "string", "null" ], "enum": [ "reported", null ] }, "filters": { "type": "object", "maxProperties": 0 }, "locale": { "const": "en" }, "max_bytes": { "type": "integer", "minimum": 1, "maximum": 1048576 }, "payee_ref": { "type": "null" }, "schema_version": { "const": "v1" }, "source_type": { "const": "ledger_period" }, "timezone": { "const": "UTC" } } } ] } } } } ], "properties": { "export_class": { "$ref": "#/components/schemas/ExportClass" }, "format": { "$ref": "#/components/schemas/ExportFormat" }, "specification": { "$ref": "#/components/schemas/ExportSpecification" }, "max_attempts": { "type": "integer", "minimum": 1, "maximum": 20, "default": 5 }, "retention_days": { "type": "integer", "minimum": 1, "maximum": 30, "default": 7 } } }, "ExportCommandRequest": { "type": "object", "additionalProperties": false, "required": [ "reason" ], "properties": { "reason": { "type": "string", "minLength": 8, "maxLength": 500 } } }, "ExportArtifactSummary": { "type": "object", "additionalProperties": false, "required": [ "artifact", "format", "media_type", "bytes", "row_count", "expires_at" ], "properties": { "artifact": { "$ref": "#/components/schemas/Uuid" }, "format": { "$ref": "#/components/schemas/ExportFormat" }, "media_type": { "type": "string", "minLength": 1, "maxLength": 120 }, "bytes": { "type": "integer", "minimum": 1 }, "row_count": { "type": [ "integer", "null" ], "minimum": 0 }, "expires_at": { "$ref": "#/components/schemas/IsoDateTime" } } }, "ExportState": { "type": "object", "additionalProperties": false, "required": [ "request", "export_class", "format", "status", "requested_at", "ready_at", "failed_at", "cancelled_at", "expired_at", "revoked_at", "expires_at", "artifact" ], "properties": { "request": { "$ref": "#/components/schemas/Uuid" }, "export_class": { "$ref": "#/components/schemas/ExportClass" }, "format": { "$ref": "#/components/schemas/ExportFormat" }, "status": { "$ref": "#/components/schemas/ExportStatus" }, "requested_at": { "$ref": "#/components/schemas/IsoDateTime" }, "ready_at": { "$ref": "#/components/schemas/NullableIsoDateTime" }, "failed_at": { "$ref": "#/components/schemas/NullableIsoDateTime" }, "cancelled_at": { "$ref": "#/components/schemas/NullableIsoDateTime" }, "expired_at": { "$ref": "#/components/schemas/NullableIsoDateTime" }, "revoked_at": { "$ref": "#/components/schemas/NullableIsoDateTime" }, "expires_at": { "$ref": "#/components/schemas/IsoDateTime" }, "artifact": { "oneOf": [ { "$ref": "#/components/schemas/ExportArtifactSummary" }, { "type": "null" } ] } } }, "ExportResponse": { "type": "object", "additionalProperties": false, "required": [ "data" ], "properties": { "data": { "$ref": "#/components/schemas/ExportState" } } }, "ExportPageResponse": { "type": "object", "additionalProperties": false, "required": [ "data", "meta" ], "properties": { "data": { "type": "array", "maxItems": 100, "items": { "$ref": "#/components/schemas/ExportState" } }, "meta": { "type": "object", "additionalProperties": false, "required": [ "next_cursor" ], "properties": { "next_cursor": { "$ref": "#/components/schemas/NullableUuid" } } } } }, "ExportCreateResponse": { "type": "object", "additionalProperties": false, "required": [ "data", "meta" ], "properties": { "data": { "$ref": "#/components/schemas/ExportState" }, "meta": { "$ref": "#/components/schemas/ReplayMeta" } } }, "CreateImportRequest": { "type": "object", "additionalProperties": false, "required": [ "source", "provider", "report_type", "file" ], "properties": { "source": { "type": "string", "pattern": "^[A-Za-z0-9][A-Za-z0-9._:-]*$", "maxLength": 120 }, "provider": { "type": "string", "minLength": 1, "maxLength": 120 }, "report_type": { "type": "string", "minLength": 1, "maxLength": 120 }, "commercial_taxonomy": { "description": "Optional approved commercial-taxonomy version to freeze for rate-capable analytics.", "allOf": [ { "$ref": "#/components/schemas/Uuid" } ] }, "statement_period": { "$ref": "#/components/schemas/StatementPeriod" }, "file": { "$ref": "#/components/schemas/ExpectedImportFile" }, "metadata": { "type": "object", "maxProperties": 50, "additionalProperties": true } } }, "StatementPeriod": { "type": "object", "additionalProperties": false, "properties": { "start": { "type": [ "string", "null" ], "format": "date" }, "end": { "type": [ "string", "null" ], "format": "date" } } }, "ExpectedImportFile": { "type": "object", "additionalProperties": false, "required": [ "original_name", "media_type", "expected_bytes", "sha256" ], "properties": { "original_name": { "type": "string", "minLength": 1, "maxLength": 500 }, "media_type": { "type": "string", "pattern": "^[A-Za-z0-9][A-Za-z0-9.+-]*/[A-Za-z0-9][A-Za-z0-9.+-]*$", "maxLength": 160 }, "expected_bytes": { "type": "integer", "minimum": 1, "maximum": 536870912000 }, "sha256": { "type": "string", "pattern": "^[a-fA-F0-9]{64}$" } } }, "ProfileImportRequest": { "type": "object", "additionalProperties": false, "properties": { "source_file_ref": { "$ref": "#/components/schemas/NullableUuid" }, "parsing": { "$ref": "#/components/schemas/ImportParsing" } } }, "ImportParsing": { "type": "object", "additionalProperties": false, "properties": { "format": { "type": "string", "enum": [ "delimited", "fixed_width", "jsonl", "xlsx" ] }, "encoding": { "type": "string", "enum": [ "UTF-8", "UTF-16LE", "UTF-16BE", "Windows-1252", "ISO-8859-1" ] }, "delimiter": { "type": "string", "enum": [ "comma", "semicolon", "tab", "pipe" ] }, "quote": { "type": "string", "enum": [ "double_quote", "none" ] }, "header_row": { "type": "integer", "minimum": 1, "maximum": 1000 }, "rows_to_skip": { "type": "integer", "minimum": 0, "maximum": 100000 }, "footer_rows": { "type": "integer", "minimum": 0, "maximum": 100000 }, "sheet_name": { "type": "string", "minLength": 1, "maxLength": 160 }, "fixed_width": { "type": "array", "minItems": 1, "maxItems": 512, "items": { "$ref": "#/components/schemas/FixedWidthColumn" } }, "record_path": { "type": "array", "minItems": 1, "maxItems": 16, "items": { "type": "string", "minLength": 1, "maxLength": 255 } }, "xml_record_path": { "type": "array", "minItems": 1, "maxItems": 16, "items": { "type": "string", "minLength": 1, "maxLength": 640 } } } }, "FixedWidthColumn": { "type": "object", "additionalProperties": false, "required": [ "source", "start", "length" ], "properties": { "source": { "type": "string", "minLength": 1, "maxLength": 255 }, "start": { "type": "integer", "minimum": 1, "maximum": 104857600 }, "length": { "type": "integer", "minimum": 1, "maximum": 104857600 }, "trim": { "type": "string", "enum": [ "both", "right", "none" ] } } }, "CancelImportRequest": { "type": "object", "additionalProperties": false, "required": [ "reason" ], "properties": { "reason": { "type": "string", "minLength": 1, "maxLength": 500 } } }, "ImportState": { "type": "string", "enum": [ "created", "uploading", "quarantined", "profiling", "awaiting_mapping", "canonicalizing", "validating", "ready_for_calculation", "calculating", "reconciled", "approved", "published", "failed", "cancelled", "rejected", "replaced", "superseded" ] }, "ImportRecord": { "type": "object", "additionalProperties": false, "required": [ "ref", "state", "source", "provider", "report_type", "statement_period", "expected_bytes", "counts" ], "properties": { "ref": { "$ref": "#/components/schemas/Uuid" }, "state": { "$ref": "#/components/schemas/ImportState" }, "source": { "type": "string", "maxLength": 120 }, "provider": { "type": "string", "maxLength": 120 }, "report_type": { "type": "string", "maxLength": 120 }, "statement_period": { "$ref": "#/components/schemas/StatementPeriod" }, "expected_bytes": { "type": "integer", "minimum": 1 }, "schema_fingerprint": { "type": [ "string", "null" ], "pattern": "^[a-f0-9]{64}$" }, "counts": { "$ref": "#/components/schemas/ImportCounts" }, "reconciliation": { "type": [ "object", "null" ], "additionalProperties": true }, "file": { "$ref": "#/components/schemas/NullableImportFile" }, "mapping": { "$ref": "#/components/schemas/NullableImportMapping" }, "profiling": { "$ref": "#/components/schemas/NullableImportProfiling" }, "profile": { "type": [ "object", "null" ], "additionalProperties": true }, "terminal_reason": { "type": [ "string", "null" ], "maxLength": 500 }, "published_at": { "$ref": "#/components/schemas/NullableIsoDateTime" }, "created_at": { "$ref": "#/components/schemas/NullableIsoDateTime" }, "updated_at": { "$ref": "#/components/schemas/NullableIsoDateTime" } } }, "ImportCounts": { "type": "object", "additionalProperties": false, "required": [ "accepted", "rejected" ], "properties": { "accepted": { "type": "integer", "minimum": 0 }, "rejected": { "type": "integer", "minimum": 0 } } }, "NullableImportFile": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/ImportFile" } ] }, "ImportFile": { "type": "object", "additionalProperties": false, "required": [ "ref", "name", "media_type", "bytes", "sha256", "verified_at" ], "properties": { "ref": { "$ref": "#/components/schemas/Uuid" }, "name": { "type": "string", "maxLength": 500 }, "media_type": { "type": "string", "maxLength": 160 }, "bytes": { "type": "integer", "minimum": 1 }, "sha256": { "type": "string", "pattern": "^[a-f0-9]{64}$" }, "verified_at": { "$ref": "#/components/schemas/NullableIsoDateTime" } } }, "NullableImportMapping": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/ImportMapping" } ] }, "ImportMapping": { "type": "object", "additionalProperties": false, "required": [ "ref", "version", "status", "schema_fingerprint" ], "properties": { "ref": { "$ref": "#/components/schemas/Uuid" }, "version": { "type": "integer", "minimum": 1 }, "status": { "type": "string", "enum": [ "draft", "approved", "superseded" ] }, "schema_fingerprint": { "type": "string", "pattern": "^[a-f0-9]{64}$" } } }, "NullableImportProfiling": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/ImportProfiling" } ] }, "ImportProfiling": { "type": "object", "additionalProperties": false, "required": [ "ref", "status", "attempts", "source_file_ref", "error_code", "completed_at" ], "properties": { "ref": { "$ref": "#/components/schemas/Uuid" }, "status": { "type": "string", "enum": [ "pending", "running", "complete", "failed", "cancelled" ] }, "attempts": { "type": "integer", "minimum": 0 }, "source_file_ref": { "$ref": "#/components/schemas/NullableUuid" }, "error_code": { "type": [ "string", "null" ], "maxLength": 120 }, "completed_at": { "$ref": "#/components/schemas/NullableIsoDateTime" } } }, "ImportResponse": { "type": "object", "additionalProperties": false, "required": [ "data" ], "properties": { "data": { "$ref": "#/components/schemas/ImportRecord" }, "meta": { "$ref": "#/components/schemas/ReplayMeta" } } }, "ImportCommandResponse": { "type": "object", "additionalProperties": false, "required": [ "data" ], "properties": { "data": { "type": "object", "additionalProperties": false, "required": [ "import" ], "properties": { "import": { "$ref": "#/components/schemas/ImportRecord" } } } } }, "ImportMappingSuggestionHeader": { "type": "object", "additionalProperties": false, "required": [ "position", "source", "key", "inferred_type", "sample_count", "null_count", "distinct_count", "suggestions" ], "properties": { "position": { "type": "integer", "minimum": 0, "maximum": 511 }, "source": { "type": "string", "maxLength": 255 }, "key": { "type": "string", "maxLength": 255 }, "inferred_type": { "type": "string", "maxLength": 40 }, "sample_count": { "type": "integer", "minimum": 0, "maximum": 100 }, "null_count": { "type": "integer", "minimum": 0, "maximum": 100 }, "distinct_count": { "type": "integer", "minimum": 0, "maximum": 100 }, "suggestions": { "type": "array", "maxItems": 3, "items": { "$ref": "#/components/schemas/MappingSuggestion" } } } }, "MappingRequiredGroup": { "type": "object", "additionalProperties": false, "required": [ "label", "any_of" ], "properties": { "label": { "type": "string", "minLength": 1, "maxLength": 120 }, "any_of": { "type": "array", "minItems": 1, "maxItems": 20, "items": { "type": "string", "minLength": 1, "maxLength": 120 } }, "covered_by_suggestion": { "type": "boolean" } } }, "ImportMappingSuggestionsResponse": { "type": "object", "additionalProperties": false, "required": [ "data" ], "properties": { "data": { "type": "object", "additionalProperties": false, "required": [ "import", "provider", "report_type", "schema_fingerprint", "format", "suggestion_policy", "headers", "required_groups", "authority" ], "properties": { "import": { "$ref": "#/components/schemas/Uuid" }, "provider": { "type": "string", "maxLength": 120 }, "report_type": { "type": "string", "maxLength": 120 }, "schema_fingerprint": { "type": "string", "pattern": "^[a-f0-9]{64}$" }, "format": { "type": "string", "maxLength": 40 }, "suggestion_policy": { "$ref": "#/components/schemas/MappingSuggestionPolicy" }, "headers": { "type": "array", "maxItems": 512, "items": { "$ref": "#/components/schemas/ImportMappingSuggestionHeader" } }, "required_groups": { "type": "array", "maxItems": 20, "items": { "allOf": [ { "$ref": "#/components/schemas/MappingRequiredGroup" }, { "type": "object", "required": [ "covered_by_suggestion" ], "properties": { "covered_by_suggestion": { "type": "boolean" } } } ] } }, "authority": { "type": "object", "additionalProperties": false, "required": [ "human_review_required", "machine_approval_allowed" ], "properties": { "human_review_required": { "type": "boolean", "const": true }, "machine_approval_allowed": { "type": "boolean", "const": false } } } } } } }, "MappingReviewPageResponse": { "type": "object", "additionalProperties": false, "required": [ "data", "meta" ], "properties": { "data": { "type": "array", "maxItems": 100, "items": { "$ref": "#/components/schemas/ImportRecord" } }, "meta": { "type": "object", "additionalProperties": false, "required": [ "next_cursor" ], "properties": { "next_cursor": { "$ref": "#/components/schemas/NullableUuid" } } } } }, "CompleteReconciliationCounts": { "type": "object", "additionalProperties": false, "required": [ "processed", "accepted", "rejected", "blank", "footer", "covered", "unreconciled" ], "properties": { "processed": { "type": "integer", "minimum": 0 }, "accepted": { "type": "integer", "minimum": 0 }, "rejected": { "type": "integer", "minimum": 0 }, "blank": { "type": "integer", "minimum": 0 }, "footer": { "type": "integer", "minimum": 0 }, "covered": { "type": "integer", "minimum": 0 }, "unreconciled": { "type": "integer", "minimum": 0 } } }, "CompleteReconciliationSummary": { "type": "object", "additionalProperties": false, "required": [ "run", "import", "provider", "report_type", "statement_period", "state", "validation_status", "counts", "balanced", "completed_at" ], "properties": { "run": { "$ref": "#/components/schemas/Uuid" }, "import": { "$ref": "#/components/schemas/Uuid" }, "provider": { "type": "string", "maxLength": 120 }, "report_type": { "type": "string", "maxLength": 120 }, "statement_period": { "$ref": "#/components/schemas/StatementPeriod" }, "state": { "$ref": "#/components/schemas/ImportState" }, "validation_status": { "type": "string", "enum": [ "passed", "failed" ] }, "counts": { "$ref": "#/components/schemas/CompleteReconciliationCounts" }, "balanced": { "type": "boolean" }, "completed_at": { "$ref": "#/components/schemas/IsoDateTime" } } }, "ReconciliationPageResponse": { "type": "object", "additionalProperties": false, "required": [ "data", "meta" ], "properties": { "data": { "type": "array", "maxItems": 100, "items": { "$ref": "#/components/schemas/CompleteReconciliationSummary" } }, "meta": { "type": "object", "additionalProperties": false, "required": [ "next_cursor" ], "properties": { "next_cursor": { "$ref": "#/components/schemas/NullableUuid" } } } } }, "ReconciliationImportFile": { "type": "object", "additionalProperties": false, "required": [ "ref", "name", "media_type", "bytes", "verified_at" ], "properties": { "ref": { "$ref": "#/components/schemas/Uuid" }, "name": { "type": "string", "maxLength": 500 }, "media_type": { "type": "string", "maxLength": 160 }, "bytes": { "type": "integer", "minimum": 1 }, "verified_at": { "$ref": "#/components/schemas/NullableIsoDateTime" } } }, "NullableReconciliationImportFile": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/ReconciliationImportFile" } ] }, "ReconciliationMapping": { "type": "object", "additionalProperties": false, "required": [ "ref", "version", "status" ], "properties": { "ref": { "$ref": "#/components/schemas/Uuid" }, "version": { "type": "integer", "minimum": 1 }, "status": { "type": "string", "enum": [ "draft", "approved", "superseded" ] } } }, "NullableReconciliationMapping": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/ReconciliationMapping" } ] }, "ReconciliationImport": { "type": "object", "additionalProperties": false, "required": [ "ref", "state", "source", "provider", "report_type", "statement_period", "file", "mapping", "terminal_reason" ], "properties": { "ref": { "$ref": "#/components/schemas/Uuid" }, "state": { "$ref": "#/components/schemas/ImportState" }, "source": { "type": "string", "maxLength": 120 }, "provider": { "type": "string", "maxLength": 120 }, "report_type": { "type": "string", "maxLength": 120 }, "statement_period": { "$ref": "#/components/schemas/StatementPeriod" }, "file": { "$ref": "#/components/schemas/NullableReconciliationImportFile" }, "mapping": { "$ref": "#/components/schemas/NullableReconciliationMapping" }, "terminal_reason": { "type": [ "string", "null" ], "maxLength": 500 } } }, "CompleteFileTotals": { "type": "object", "propertyNames": { "pattern": "^[A-Z]{3}$" }, "maxProperties": 180, "additionalProperties": { "$ref": "#/components/schemas/MappingSampleCurrencyTotals" } }, "CompleteFileReconciliation": { "type": "object", "additionalProperties": false, "required": [ "balanced", "covered_rows", "unreconciled_rows", "differences" ], "properties": { "balanced": { "type": "boolean" }, "covered_rows": { "type": "integer", "minimum": 0 }, "unreconciled_rows": { "type": "integer", "minimum": 0 }, "differences": { "$ref": "#/components/schemas/CompleteFileTotals" } } }, "CanonicalizationEvidence": { "type": "object", "additionalProperties": false, "required": [ "ref", "status", "engine_version", "schema_version", "processed_rows", "accepted_rows", "rejected_rows", "blank_rows", "footer_rows", "source_totals", "mapped_totals", "rejected_totals", "reconciliation", "completed_at" ], "properties": { "ref": { "$ref": "#/components/schemas/Uuid" }, "status": { "type": "string", "const": "complete" }, "engine_version": { "type": "string", "minLength": 1, "maxLength": 120 }, "schema_version": { "type": "string", "minLength": 1, "maxLength": 120 }, "processed_rows": { "type": "integer", "minimum": 0 }, "accepted_rows": { "type": "integer", "minimum": 0 }, "rejected_rows": { "type": "integer", "minimum": 0 }, "blank_rows": { "type": "integer", "minimum": 0 }, "footer_rows": { "type": "integer", "minimum": 0 }, "source_totals": { "$ref": "#/components/schemas/CompleteFileTotals" }, "mapped_totals": { "$ref": "#/components/schemas/CompleteFileTotals" }, "rejected_totals": { "$ref": "#/components/schemas/CompleteFileTotals" }, "reconciliation": { "$ref": "#/components/schemas/CompleteFileReconciliation" }, "completed_at": { "$ref": "#/components/schemas/IsoDateTime" } } }, "ValidationEvidence": { "type": "object", "additionalProperties": false, "required": [ "ref", "status", "run_number", "accepted_rows", "rejected_rows", "source_totals", "mapped_totals", "reconciliation", "failure_summary", "completed_at" ], "properties": { "ref": { "$ref": "#/components/schemas/Uuid" }, "status": { "type": "string", "enum": [ "passed", "failed" ] }, "run_number": { "type": "integer", "minimum": 1 }, "accepted_rows": { "type": "integer", "minimum": 0 }, "rejected_rows": { "type": "integer", "minimum": 0 }, "source_totals": { "$ref": "#/components/schemas/CompleteFileTotals" }, "mapped_totals": { "$ref": "#/components/schemas/CompleteFileTotals" }, "reconciliation": { "$ref": "#/components/schemas/CompleteFileReconciliation" }, "failure_summary": { "type": [ "object", "null" ], "additionalProperties": true }, "completed_at": { "$ref": "#/components/schemas/IsoDateTime" } } }, "CompleteReconciliationDetail": { "type": "object", "additionalProperties": false, "required": [ "import", "canonicalization", "validation" ], "properties": { "import": { "$ref": "#/components/schemas/ReconciliationImport" }, "canonicalization": { "$ref": "#/components/schemas/CanonicalizationEvidence" }, "validation": { "$ref": "#/components/schemas/ValidationEvidence" }, "publication": { "$ref": "#/components/schemas/NullablePublicationReconciliationEvidence" } } }, "CalculationSourceCurrencyTotals": { "type": "object", "additionalProperties": false, "required": [ "gross", "net" ], "properties": { "gross": { "$ref": "#/components/schemas/SignedCanonicalDecimal" }, "net": { "$ref": "#/components/schemas/SignedCanonicalDecimal" } } }, "CalculationSourceTotals": { "type": "object", "propertyNames": { "pattern": "^[A-Z]{3}$" }, "maxProperties": 180, "additionalProperties": { "$ref": "#/components/schemas/CalculationSourceCurrencyTotals" } }, "CalculationResultCurrencyTotals": { "type": "object", "additionalProperties": false, "required": [ "earnings", "reserves", "fees", "deductions", "recoupment", "withholding", "payable" ], "properties": { "earnings": { "$ref": "#/components/schemas/SignedCanonicalDecimal" }, "reserves": { "$ref": "#/components/schemas/SignedCanonicalDecimal" }, "fees": { "$ref": "#/components/schemas/SignedCanonicalDecimal" }, "deductions": { "$ref": "#/components/schemas/SignedCanonicalDecimal" }, "recoupment": { "$ref": "#/components/schemas/SignedCanonicalDecimal" }, "withholding": { "$ref": "#/components/schemas/SignedCanonicalDecimal" }, "payable": { "$ref": "#/components/schemas/SignedCanonicalDecimal" } } }, "CalculationResultTotals": { "type": "object", "propertyNames": { "pattern": "^[A-Z]{3}$" }, "maxProperties": 180, "additionalProperties": { "$ref": "#/components/schemas/CalculationResultCurrencyTotals" } }, "PayableTotals": { "type": "object", "propertyNames": { "pattern": "^[A-Z]{3}$" }, "maxProperties": 180, "additionalProperties": { "$ref": "#/components/schemas/SignedCanonicalDecimal" } }, "PublicationReconciliationReport": { "type": "object", "additionalProperties": false, "required": [ "scope", "balanced", "import", "canonicalization", "analytics", "calculation", "allocations", "ledger", "statements" ], "properties": { "scope": { "type": "string", "const": "published_generation" }, "balanced": { "type": "boolean", "const": true }, "import": { "$ref": "#/components/schemas/Uuid" }, "canonicalization": { "type": "object", "additionalProperties": false, "required": [ "ref", "rows", "totals" ], "properties": { "ref": { "$ref": "#/components/schemas/Uuid" }, "rows": { "type": "integer", "minimum": 0 }, "totals": { "$ref": "#/components/schemas/CompleteFileTotals" } } }, "analytics": { "type": "object", "additionalProperties": false, "required": [ "ref", "status", "facts_rows", "cube_rows", "facts_totals", "cube_totals" ], "properties": { "ref": { "$ref": "#/components/schemas/Uuid" }, "status": { "type": "string", "enum": [ "published", "superseded" ] }, "facts_rows": { "type": "integer", "minimum": 0 }, "cube_rows": { "type": "integer", "minimum": 0 }, "rate_required": { "type": "boolean" }, "rate_rows": { "type": "integer", "minimum": 0 }, "rate_groups": { "type": "integer", "minimum": 0 }, "facts_totals": { "$ref": "#/components/schemas/CompleteFileTotals" }, "cube_totals": { "$ref": "#/components/schemas/CompleteFileTotals" } } }, "calculation": { "type": "object", "additionalProperties": false, "required": [ "ref", "source_totals", "result_totals" ], "properties": { "ref": { "$ref": "#/components/schemas/Uuid" }, "source_totals": { "$ref": "#/components/schemas/CalculationSourceTotals" }, "result_totals": { "$ref": "#/components/schemas/CalculationResultTotals" } } }, "allocations": { "type": "object", "additionalProperties": false, "required": [ "count", "totals" ], "properties": { "count": { "type": "integer", "minimum": 1 }, "totals": { "$ref": "#/components/schemas/CalculationResultTotals" } } }, "ledger": { "type": "object", "additionalProperties": false, "required": [ "count", "payable_totals" ], "properties": { "count": { "type": "integer", "minimum": 1 }, "payable_totals": { "$ref": "#/components/schemas/PayableTotals" } } }, "statements": { "type": "object", "additionalProperties": false, "required": [ "count", "totals" ], "properties": { "count": { "type": "integer", "minimum": 1 }, "totals": { "$ref": "#/components/schemas/CalculationResultTotals" } } } } }, "PublicationReconciliationEvidence": { "type": "object", "additionalProperties": false, "required": [ "ref", "reconciled_at", "report" ], "properties": { "ref": { "$ref": "#/components/schemas/Uuid" }, "reconciled_at": { "$ref": "#/components/schemas/IsoDateTime" }, "report": { "$ref": "#/components/schemas/PublicationReconciliationReport" } } }, "NullablePublicationReconciliationEvidence": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/PublicationReconciliationEvidence" } ] }, "ReconciliationDetailResponse": { "type": "object", "additionalProperties": false, "required": [ "data" ], "properties": { "data": { "$ref": "#/components/schemas/CompleteReconciliationDetail" } } }, "MappingDefinitionRequest": { "type": "object", "additionalProperties": false, "required": [ "profile", "mapping" ], "properties": { "profile": { "$ref": "#/components/schemas/SourceProfileSelection" }, "mapping": { "$ref": "#/components/schemas/MappingDefinition" } } }, "SourceProfileSelection": { "type": "object", "additionalProperties": false, "anyOf": [ { "required": [ "ref" ] }, { "required": [ "name" ] } ], "properties": { "ref": { "$ref": "#/components/schemas/NullableUuid" }, "name": { "type": [ "string", "null" ], "minLength": 1, "maxLength": 160 }, "filename_rules": { "type": "array", "maxItems": 20, "items": { "$ref": "#/components/schemas/SourceSelectionRule" } }, "archive_member_rules": { "type": "array", "maxItems": 20, "items": { "$ref": "#/components/schemas/SourceSelectionRule" } }, "sheet_name": { "type": [ "string", "null" ], "minLength": 1, "maxLength": 160 } } }, "SourceSelectionRule": { "type": "object", "additionalProperties": false, "required": [ "match", "value" ], "properties": { "match": { "type": "string", "enum": [ "exact", "prefix", "suffix" ] }, "value": { "type": "string", "minLength": 1, "maxLength": 500 } } }, "MappingDefinition": { "type": "object", "additionalProperties": false, "required": [ "columns" ], "properties": { "columns": { "type": "array", "minItems": 1, "maxItems": 512, "items": { "$ref": "#/components/schemas/MappingColumn" } }, "validation_rules": { "type": "array", "maxItems": 100, "items": { "type": "object", "additionalProperties": true } }, "reconciliation_rules": { "type": "array", "maxItems": 100, "items": { "type": "object", "additionalProperties": true } } } }, "MappingColumn": { "type": "object", "additionalProperties": false, "required": [ "source", "target" ], "properties": { "source": { "type": "string", "minLength": 1, "maxLength": 255 }, "target": { "type": "string", "minLength": 1, "maxLength": 120 }, "transforms": { "type": "array", "maxItems": 20, "items": { "$ref": "#/components/schemas/MappingTransform" } } } }, "MappingTransform": { "type": "object", "additionalProperties": false, "required": [ "op" ], "properties": { "op": { "type": "string", "enum": [ "trim", "lowercase", "uppercase", "null_if_empty", "default", "replace", "lookup", "parse_decimal", "parse_date", "negate", "absolute", "prefix", "suffix" ] }, "value": { "type": [ "string", "integer", "boolean", "null" ] }, "from": { "type": "string" }, "to": { "type": "string" }, "map": { "type": "object", "maxProperties": 1000, "additionalProperties": true }, "default": { "type": [ "string", "integer", "boolean", "null" ] }, "decimal_separator": { "type": "string", "enum": [ ".", "," ] }, "thousands_separator": { "type": [ "string", "null" ], "enum": [ ".", ",", " ", "'", null ] }, "formats": { "type": "array", "minItems": 1, "maxItems": 7, "items": { "type": "string" } } } }, "MappingReviewProfile": { "type": "object", "additionalProperties": false, "required": [ "schema_fingerprint", "format", "sheet_name", "sampled_rows", "headers" ], "properties": { "schema_fingerprint": { "type": [ "string", "null" ], "pattern": "^[a-f0-9]{64}$" }, "suggestion_policy": { "$ref": "#/components/schemas/MappingSuggestionPolicy" }, "format": { "type": [ "string", "null" ], "enum": [ "delimited", "fixed_width", "jsonl", "xlsx", null ] }, "sheet_name": { "type": [ "string", "null" ], "maxLength": 160 }, "record_path": { "type": [ "array", "null" ], "minItems": 1, "maxItems": 16, "items": { "type": "string", "minLength": 1, "maxLength": 255 } }, "adapter": { "type": [ "string", "null" ], "enum": [ "xml", null ] }, "sampled_rows": { "type": "integer", "minimum": 0, "maximum": 100 }, "required_groups": { "type": "array", "maxItems": 20, "items": { "$ref": "#/components/schemas/MappingRequiredGroup" } }, "headers": { "type": "array", "maxItems": 512, "items": { "$ref": "#/components/schemas/MappingProfileHeader" } } } }, "MappingProfileHeader": { "type": "object", "additionalProperties": true, "required": [ "position", "source", "key", "sample_values", "sample_count", "null_count", "distinct_count", "inferred_type", "suggestions" ], "properties": { "position": { "type": "integer", "minimum": 0, "maximum": 511 }, "source": { "type": "string", "maxLength": 255 }, "key": { "type": "string", "maxLength": 255 }, "sample_values": { "type": "array", "maxItems": 5, "items": { "type": [ "string", "null" ], "maxLength": 2000 } }, "sample_count": { "type": "integer", "minimum": 0, "maximum": 100 }, "null_count": { "type": "integer", "minimum": 0, "maximum": 100 }, "distinct_count": { "type": "integer", "minimum": 0, "maximum": 100 }, "inferred_type": { "type": "string", "maxLength": 40 }, "suggestions": { "type": "array", "maxItems": 10, "items": { "$ref": "#/components/schemas/MappingSuggestion" } } } }, "MappingSuggestion": { "type": "object", "additionalProperties": false, "required": [ "field", "confidence", "reason" ], "properties": { "field": { "type": "string", "maxLength": 120 }, "confidence": { "type": "string", "pattern": "^(?:0(?:\\.\\d{1,10})?|1(?:\\.0{1,10})?)$" }, "reason": { "type": "string", "maxLength": 80 } } }, "MappingSuggestionPolicy": { "type": "object", "additionalProperties": false, "required": [ "engine", "canonical_schema", "provider_aliases", "provider_aliases_sha256", "bulk_apply_min_confidence" ], "properties": { "engine": { "type": "string", "const": "column-suggestion-v1" }, "canonical_schema": { "type": "string", "pattern": "^canonical-schema-v[1-9][0-9]*$" }, "provider_aliases": { "type": "string", "const": "provider-mapping-aliases-v1" }, "provider_aliases_sha256": { "type": "string", "pattern": "^[a-f0-9]{64}$" }, "bulk_apply_min_confidence": { "type": "string", "const": "0.90" } } }, "MappingCoverage": { "type": "object", "additionalProperties": false, "required": [ "source_columns", "mapped_columns", "unmapped_sources" ], "properties": { "source_columns": { "type": "integer", "minimum": 0, "maximum": 512 }, "mapped_columns": { "type": "integer", "minimum": 0, "maximum": 512 }, "unmapped_sources": { "type": "array", "maxItems": 512, "items": { "type": "string", "maxLength": 255 } } } }, "MappingPreviewResult": { "type": "object", "additionalProperties": false, "required": [ "rows", "errors", "error_count" ], "properties": { "rows": { "type": "array", "maxItems": 100, "items": { "type": "object", "additionalProperties": true } }, "errors": { "type": "array", "maxItems": 100, "items": { "type": "object", "additionalProperties": true } }, "error_count": { "type": "integer", "minimum": 0 }, "reconciliation": { "$ref": "#/components/schemas/MappingSampleReconciliation" } } }, "SignedCanonicalDecimal": { "type": "string", "pattern": "^-?(?:0|[1-9][0-9]{0,25})\\.[0-9]{12}$" }, "MappingSampleCurrencyTotals": { "type": "object", "additionalProperties": false, "properties": { "units": { "$ref": "#/components/schemas/SignedCanonicalDecimal" }, "duration_seconds": { "$ref": "#/components/schemas/SignedCanonicalDecimal" }, "gross_revenue": { "$ref": "#/components/schemas/SignedCanonicalDecimal" }, "deductions": { "$ref": "#/components/schemas/SignedCanonicalDecimal" }, "taxes": { "$ref": "#/components/schemas/SignedCanonicalDecimal" }, "costs": { "$ref": "#/components/schemas/SignedCanonicalDecimal" }, "net_revenue": { "$ref": "#/components/schemas/SignedCanonicalDecimal" } } }, "MappingSampleCurrencyCoverage": { "type": "object", "additionalProperties": false, "properties": { "units": { "type": "integer", "minimum": 0, "maximum": 100 }, "duration_seconds": { "type": "integer", "minimum": 0, "maximum": 100 }, "gross_revenue": { "type": "integer", "minimum": 0, "maximum": 100 }, "deductions": { "type": "integer", "minimum": 0, "maximum": 100 }, "taxes": { "type": "integer", "minimum": 0, "maximum": 100 }, "costs": { "type": "integer", "minimum": 0, "maximum": 100 }, "net_revenue": { "type": "integer", "minimum": 0, "maximum": 100 } } }, "MappingSampleTotals": { "type": "object", "propertyNames": { "pattern": "^[A-Z]{3}$" }, "maxProperties": 180, "additionalProperties": { "$ref": "#/components/schemas/MappingSampleCurrencyTotals" } }, "MappingSampleCoverage": { "type": "object", "propertyNames": { "pattern": "^[A-Z]{3}$" }, "maxProperties": 180, "additionalProperties": { "$ref": "#/components/schemas/MappingSampleCurrencyCoverage" } }, "MappingSampleReconciliation": { "type": "object", "additionalProperties": false, "required": [ "scope", "complete_file", "currency_basis", "sampled_rows", "covered_rows", "unreconciled_rows", "source_totals", "mapped_totals", "rejected_totals", "differences", "coverage_rows", "balanced" ], "properties": { "scope": { "type": "string", "const": "profile_sample" }, "complete_file": { "type": "boolean", "const": false }, "currency_basis": { "type": "string", "const": "reported_currency_then_settlement_currency" }, "sampled_rows": { "type": "integer", "minimum": 0, "maximum": 100 }, "covered_rows": { "type": "integer", "minimum": 0, "maximum": 100 }, "unreconciled_rows": { "type": "integer", "minimum": 0, "maximum": 100 }, "source_totals": { "$ref": "#/components/schemas/MappingSampleTotals" }, "mapped_totals": { "$ref": "#/components/schemas/MappingSampleTotals" }, "rejected_totals": { "$ref": "#/components/schemas/MappingSampleTotals" }, "differences": { "$ref": "#/components/schemas/MappingSampleTotals" }, "coverage_rows": { "$ref": "#/components/schemas/MappingSampleCoverage" }, "balanced": { "type": "boolean" } } }, "MappingPreviewResponse": { "type": "object", "additionalProperties": false, "required": [ "data" ], "properties": { "data": { "type": "object", "additionalProperties": false, "required": [ "import", "profile", "selection", "mapping", "coverage", "preview" ], "properties": { "import": { "$ref": "#/components/schemas/ImportRecord" }, "profile": { "$ref": "#/components/schemas/MappingReviewProfile" }, "selection": { "$ref": "#/components/schemas/SourceProfileSelection" }, "mapping": { "$ref": "#/components/schemas/MappingDefinition" }, "coverage": { "$ref": "#/components/schemas/MappingCoverage" }, "preview": { "$ref": "#/components/schemas/MappingPreviewResult" } } } } }, "MappingApprovalResponse": { "type": "object", "additionalProperties": false, "required": [ "data" ], "properties": { "data": { "type": "object", "additionalProperties": false, "required": [ "import", "mapping", "preview" ], "properties": { "import": { "$ref": "#/components/schemas/ImportRecord" }, "mapping": { "$ref": "#/components/schemas/ImportMapping" }, "preview": { "$ref": "#/components/schemas/MappingPreviewResult" } } } } }, "RejectMappingProposalRequest": { "type": "object", "additionalProperties": false, "required": [ "reason" ], "properties": { "reason": { "type": "string", "minLength": 1, "maxLength": 500 } } }, "MappingProposal": { "type": "object", "additionalProperties": false, "required": [ "ref", "version", "status", "profile", "mapping", "proposed_by", "proposed_at", "decided_by", "decided_at", "decision_reason" ], "properties": { "ref": { "$ref": "#/components/schemas/Uuid" }, "version": { "type": "integer", "minimum": 1 }, "status": { "type": "string", "enum": [ "pending", "approved", "rejected" ] }, "profile": { "$ref": "#/components/schemas/SourceProfileSelection" }, "mapping": { "$ref": "#/components/schemas/MappingDefinition" }, "proposed_by": { "$ref": "#/components/schemas/Uuid" }, "proposed_at": { "$ref": "#/components/schemas/IsoDateTime" }, "decided_by": { "$ref": "#/components/schemas/NullableUuid" }, "decided_at": { "$ref": "#/components/schemas/NullableIsoDateTime" }, "decision_reason": { "type": [ "string", "null" ], "maxLength": 500 } } }, "MappingProposalPolicyResponse": { "type": "object", "additionalProperties": false, "required": [ "data" ], "properties": { "data": { "type": "object", "additionalProperties": false, "required": [ "maker_checker_required", "proposal" ], "properties": { "maker_checker_required": { "type": "boolean" }, "proposal": { "oneOf": [ { "$ref": "#/components/schemas/MappingProposal" }, { "type": "null" } ] } } } } }, "MappingProposalResponse": { "type": "object", "additionalProperties": false, "required": [ "data" ], "properties": { "data": { "type": "object", "additionalProperties": false, "required": [ "proposal", "replayed" ], "properties": { "proposal": { "$ref": "#/components/schemas/MappingProposal" }, "replayed": { "type": "boolean" } } } } }, "MappingProposalDecisionResponse": { "type": "object", "additionalProperties": false, "required": [ "data" ], "properties": { "data": { "type": "object", "additionalProperties": false, "required": [ "proposal", "replayed" ], "properties": { "proposal": { "$ref": "#/components/schemas/MappingProposal" }, "approval": { "type": "object", "additionalProperties": false, "required": [ "import", "mapping", "preview" ], "properties": { "import": { "$ref": "#/components/schemas/ImportRecord" }, "mapping": { "$ref": "#/components/schemas/ImportMapping" }, "preview": { "$ref": "#/components/schemas/MappingPreviewResult" } } }, "replayed": { "type": "boolean" } } } } }, "ImportProfileResponse": { "type": "object", "additionalProperties": false, "required": [ "data" ], "properties": { "data": { "type": "object", "additionalProperties": false, "required": [ "import", "profiling" ], "properties": { "import": { "$ref": "#/components/schemas/ImportRecord" }, "profiling": { "type": "object", "additionalProperties": false, "required": [ "ref", "status" ], "properties": { "ref": { "$ref": "#/components/schemas/Uuid" }, "status": { "type": "string", "enum": [ "pending", "running", "complete", "failed", "cancelled" ] } } } } } } }, "ReplayMeta": { "type": "object", "additionalProperties": false, "required": [ "idempotent_replay" ], "properties": { "idempotent_replay": { "type": "boolean" } } }, "UploadSessionResponse": { "type": "object", "additionalProperties": false, "required": [ "data", "meta" ], "properties": { "data": { "$ref": "#/components/schemas/UploadSessionAuthority" }, "meta": { "$ref": "#/components/schemas/ReplayMeta" } } }, "UploadSessionAuthority": { "type": "object", "additionalProperties": false, "required": [ "upload_session", "creation_endpoint", "authorization", "metadata", "expected_bytes", "expires_at" ], "properties": { "upload_session": { "$ref": "#/components/schemas/Uuid" }, "creation_endpoint": { "type": "string", "minLength": 1, "maxLength": 500 }, "authorization": { "type": "object", "additionalProperties": false, "required": [ "scheme", "token" ], "properties": { "scheme": { "type": "string", "const": "Bearer" }, "token": { "type": "string", "minLength": 1, "maxLength": 256 } } }, "metadata": { "type": "object", "additionalProperties": false, "required": [ "session" ], "properties": { "session": { "$ref": "#/components/schemas/Uuid" } } }, "expected_bytes": { "type": "integer", "minimum": 1 }, "expires_at": { "$ref": "#/components/schemas/IsoDateTime" } } }, "TenantRole": { "type": "string", "enum": [ "platform_operator", "tenant_owner", "finance_approver", "royalty_manager", "catalog_manager", "uploader", "analyst", "auditor", "payee" ] }, "ErrorDetail": { "type": "object", "additionalProperties": false, "required": [ "code", "message", "correlation" ], "properties": { "code": { "type": "string", "minLength": 1, "maxLength": 120 }, "message": { "type": "string", "minLength": 1, "maxLength": 500 }, "correlation": { "$ref": "#/components/schemas/Uuid" }, "fields": { "type": "object", "additionalProperties": { "type": "array", "items": { "type": "string" } } } } }, "ErrorResponse": { "type": "object", "additionalProperties": false, "required": [ "error" ], "properties": { "error": { "$ref": "#/components/schemas/ErrorDetail" } } }, "WebhookIngressPayload": { "type": "object", "minProperties": 1, "maxProperties": 256, "additionalProperties": true }, "WebhookIngressResult": { "type": "object", "additionalProperties": false, "required": [ "receipt", "status" ], "properties": { "receipt": { "$ref": "#/components/schemas/Uuid" }, "status": { "type": "string", "const": "accepted" } } }, "WebhookIngressResponse": { "type": "object", "additionalProperties": false, "required": [ "data" ], "properties": { "data": { "$ref": "#/components/schemas/WebhookIngressResult" } } }, "LoginRequest": { "type": "object", "additionalProperties": false, "required": [ "email", "password", "tenant" ], "properties": { "email": { "type": "string", "format": "email", "maxLength": 254 }, "password": { "type": "string", "maxLength": 128 }, "tenant": { "$ref": "#/components/schemas/Uuid" } } }, "AcceptNewInvitationRequest": { "type": "object", "additionalProperties": false, "required": [ "token", "name", "password" ], "properties": { "token": { "type": "string", "maxLength": 128 }, "name": { "type": "string", "maxLength": 160 }, "password": { "type": "string", "minLength": 14, "maxLength": 128 } } }, "AcceptExistingInvitationRequest": { "type": "object", "additionalProperties": false, "required": [ "token" ], "properties": { "token": { "type": "string", "maxLength": 128 } } }, "StartMfaEnrollmentRequest": { "type": "object", "additionalProperties": false, "required": [ "label" ], "properties": { "label": { "type": "string", "maxLength": 120 } } }, "VerifyMfaRequest": { "type": "object", "additionalProperties": false, "required": [ "factor", "code" ], "properties": { "factor": { "$ref": "#/components/schemas/Uuid" }, "code": { "type": "string", "pattern": "^\\d{6}$" } } }, "RecoverMfaRequest": { "type": "object", "additionalProperties": false, "required": [ "factor", "recovery_code" ], "properties": { "factor": { "$ref": "#/components/schemas/Uuid" }, "recovery_code": { "type": "string", "maxLength": 64 } } }, "PlatformSession": { "type": "object", "additionalProperties": false, "required": [ "identity", "tenant", "role", "mfa_required", "mfa_verified", "mfa_method", "mfa_factor", "mfa_factor_type" ], "properties": { "identity": { "$ref": "#/components/schemas/Uuid" }, "tenant": { "$ref": "#/components/schemas/Uuid" }, "role": { "$ref": "#/components/schemas/TenantRole" }, "mfa_required": { "type": "boolean" }, "mfa_verified": { "type": "boolean" }, "mfa_method": { "type": [ "string", "null" ], "enum": [ "totp", "recovery", null ] }, "mfa_factor": { "$ref": "#/components/schemas/NullableUuid" }, "mfa_factor_type": { "type": [ "string", "null" ], "enum": [ "totp", null ] } } }, "PlatformSessionResponse": { "type": "object", "additionalProperties": false, "required": [ "data" ], "properties": { "data": { "$ref": "#/components/schemas/PlatformSession" } } }, "RevokeIdentitySessionRequest": { "type": "object", "additionalProperties": false, "required": [ "reason" ], "properties": { "reason": { "type": "string", "minLength": 8, "maxLength": 500 } } }, "IdentitySession": { "type": "object", "additionalProperties": false, "required": [ "session", "current", "status", "device_class", "device_label", "established_at", "last_seen_at", "mfa_verified_at", "ended_at", "revoked_at" ], "properties": { "session": { "$ref": "#/components/schemas/Uuid" }, "current": { "type": "boolean" }, "status": { "type": "string", "enum": [ "active", "ended", "revoked" ] }, "device_class": { "type": "string", "enum": [ "desktop", "mobile", "tablet", "unknown" ] }, "device_label": { "type": "string", "minLength": 1, "maxLength": 120 }, "established_at": { "$ref": "#/components/schemas/IsoDateTime" }, "last_seen_at": { "$ref": "#/components/schemas/IsoDateTime" }, "mfa_verified_at": { "$ref": "#/components/schemas/NullableIsoDateTime" }, "ended_at": { "$ref": "#/components/schemas/NullableIsoDateTime" }, "revoked_at": { "$ref": "#/components/schemas/NullableIsoDateTime" } } }, "IdentitySessionPageResponse": { "type": "object", "additionalProperties": false, "required": [ "data" ], "properties": { "data": { "type": "array", "maxItems": 50, "items": { "$ref": "#/components/schemas/IdentitySession" } } } }, "IdentitySessionRevocation": { "type": "object", "additionalProperties": false, "required": [ "session", "status", "revoked_at" ], "properties": { "session": { "$ref": "#/components/schemas/Uuid" }, "status": { "type": "string", "const": "revoked" }, "revoked_at": { "$ref": "#/components/schemas/IsoDateTime" } } }, "IdentitySessionRevocationResponse": { "type": "object", "additionalProperties": false, "required": [ "data" ], "properties": { "data": { "$ref": "#/components/schemas/IdentitySessionRevocation" } } }, "InvitationAcceptance": { "type": "object", "additionalProperties": false, "required": [ "tenant", "role", "status" ], "properties": { "tenant": { "$ref": "#/components/schemas/Uuid" }, "role": { "$ref": "#/components/schemas/TenantRole" }, "status": { "type": "string", "enum": [ "active" ] } } }, "InvitationAcceptanceResponse": { "type": "object", "additionalProperties": false, "required": [ "data" ], "properties": { "data": { "$ref": "#/components/schemas/InvitationAcceptance" } } }, "MfaEnrollment": { "type": "object", "additionalProperties": false, "required": [ "factor", "type", "secret", "provisioning_uri" ], "properties": { "factor": { "$ref": "#/components/schemas/Uuid" }, "type": { "type": "string", "enum": [ "totp" ] }, "secret": { "type": "string", "minLength": 16, "maxLength": 128 }, "provisioning_uri": { "type": "string", "format": "uri", "maxLength": 2048 } } }, "MfaEnrollmentResponse": { "type": "object", "additionalProperties": false, "required": [ "data" ], "properties": { "data": { "$ref": "#/components/schemas/MfaEnrollment" } } }, "MfaConfirmation": { "type": "object", "additionalProperties": false, "required": [ "factor", "recovery_codes", "mfa_verified" ], "properties": { "factor": { "$ref": "#/components/schemas/Uuid" }, "recovery_codes": { "type": "array", "minItems": 1, "items": { "type": "string", "minLength": 1, "maxLength": 64 } }, "mfa_verified": { "type": "boolean" } } }, "MfaConfirmationResponse": { "type": "object", "additionalProperties": false, "required": [ "data" ], "properties": { "data": { "$ref": "#/components/schemas/MfaConfirmation" } } }, "OAuthTokenRequest": { "type": "object", "additionalProperties": false, "required": [ "grant_type" ], "properties": { "grant_type": { "type": "string", "const": "client_credentials" }, "scope": { "type": [ "string", "null" ], "maxLength": 1000 } } }, "OAuthTokenResponse": { "type": "object", "additionalProperties": false, "required": [ "access_token", "token_type", "expires_in", "scope" ], "properties": { "access_token": { "type": "string", "minLength": 32, "maxLength": 128 }, "token_type": { "type": "string", "const": "Bearer" }, "expires_in": { "type": "integer", "minimum": 0, "maximum": 3600 }, "scope": { "type": "string", "maxLength": 1000 } } }, "ApiSession": { "type": "object", "additionalProperties": false, "required": [ "client", "tenant", "scopes", "expires_at" ], "properties": { "client": { "$ref": "#/components/schemas/Uuid" }, "tenant": { "$ref": "#/components/schemas/Uuid" }, "scopes": { "type": "array", "items": { "$ref": "#/components/schemas/Scope" } }, "expires_at": { "$ref": "#/components/schemas/IsoDateTime" } } }, "ApiSessionResponse": { "type": "object", "additionalProperties": false, "required": [ "data" ], "properties": { "data": { "$ref": "#/components/schemas/ApiSession" } } }, "CreateApiClientRequest": { "type": "object", "additionalProperties": false, "required": [ "name", "scopes" ], "properties": { "name": { "type": "string", "maxLength": 160 }, "scopes": { "type": "array", "minItems": 1, "maxItems": 32, "uniqueItems": true, "items": { "$ref": "#/components/schemas/Scope" } }, "expires_at": { "$ref": "#/components/schemas/NullableIsoDateTime" } } }, "UpdateApiClientRequest": { "type": "object", "additionalProperties": false, "required": [ "name", "expires_at" ], "properties": { "name": { "type": "string", "maxLength": 160 }, "expires_at": { "$ref": "#/components/schemas/NullableIsoDateTime" } } }, "RotateApiClientRequest": { "type": "object", "additionalProperties": false, "properties": { "overlap_seconds": { "type": "integer", "minimum": 60, "maximum": 86400, "default": 300 } } }, "ReplaceApiClientScopesRequest": { "type": "object", "additionalProperties": false, "required": [ "scopes" ], "properties": { "scopes": { "type": "array", "minItems": 1, "maxItems": 32, "uniqueItems": true, "items": { "$ref": "#/components/schemas/Scope" } } } }, "ManagedApiClient": { "type": "object", "additionalProperties": false, "required": [ "client", "name", "scopes", "status", "expires_at", "replayed" ], "properties": { "client": { "$ref": "#/components/schemas/Uuid" }, "name": { "type": "string", "maxLength": 160 }, "scopes": { "type": "array", "items": { "$ref": "#/components/schemas/Scope" } }, "status": { "type": "string", "enum": [ "active", "disabled", "revoked" ] }, "expires_at": { "$ref": "#/components/schemas/NullableIsoDateTime" }, "replayed": { "type": "boolean" }, "secret": { "type": "string", "minLength": 32, "maxLength": 128 } } }, "ManagedApiClientResponse": { "type": "object", "additionalProperties": false, "required": [ "data" ], "properties": { "data": { "$ref": "#/components/schemas/ManagedApiClient" } } }, "ApiClientInventoryItem": { "type": "object", "additionalProperties": false, "required": [ "client", "name", "secret_prefix", "scopes", "status", "expires_at", "last_used_at", "rotated_at", "secret_version" ], "properties": { "client": { "$ref": "#/components/schemas/Uuid" }, "name": { "type": "string", "maxLength": 160 }, "secret_prefix": { "type": "string", "minLength": 1, "maxLength": 16 }, "scopes": { "type": "array", "items": { "$ref": "#/components/schemas/Scope" } }, "status": { "type": "string", "enum": [ "active", "disabled", "revoked" ] }, "expires_at": { "$ref": "#/components/schemas/NullableIsoDateTime" }, "last_used_at": { "$ref": "#/components/schemas/NullableIsoDateTime" }, "rotated_at": { "$ref": "#/components/schemas/NullableIsoDateTime" }, "secret_version": { "type": "integer", "minimum": 1 } } }, "ApiTokenInventoryItem": { "type": "object", "additionalProperties": false, "required": [ "token", "token_prefix", "scopes", "status", "expires_at", "last_used_at", "revoked_at" ], "properties": { "token": { "$ref": "#/components/schemas/Uuid" }, "token_prefix": { "type": "string", "minLength": 1, "maxLength": 16 }, "scopes": { "type": "array", "items": { "$ref": "#/components/schemas/Scope" } }, "status": { "type": "string", "enum": [ "active", "expired", "revoked" ] }, "expires_at": { "$ref": "#/components/schemas/IsoDateTime" }, "last_used_at": { "$ref": "#/components/schemas/NullableIsoDateTime" }, "revoked_at": { "$ref": "#/components/schemas/NullableIsoDateTime" } } }, "CursorMeta": { "type": "object", "additionalProperties": false, "required": [ "next_cursor" ], "properties": { "next_cursor": { "$ref": "#/components/schemas/NullableUuid" } } }, "ApiClientPage": { "type": "object", "additionalProperties": false, "required": [ "data", "meta" ], "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/ApiClientInventoryItem" } }, "meta": { "$ref": "#/components/schemas/CursorMeta" } } }, "ApiTokenPage": { "type": "object", "additionalProperties": false, "required": [ "data", "meta" ], "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/ApiTokenInventoryItem" } }, "meta": { "$ref": "#/components/schemas/CursorMeta" } } }, "CatalogReviewStateValue": { "type": "string", "enum": [ "unreviewed", "held", "released" ] }, "CatalogEntitySummary": { "type": "object", "additionalProperties": false, "required": [ "entity", "entity_type", "snapshot", "version", "display_name", "identifier_count", "effective_from", "effective_to", "recorded_at" ], "properties": { "entity": { "$ref": "#/components/schemas/Uuid" }, "entity_type": { "type": "string", "enum": [ "recording", "release", "work", "party" ] }, "snapshot": { "$ref": "#/components/schemas/Uuid" }, "version": { "type": "integer", "minimum": 1 }, "display_name": { "type": "string", "minLength": 1, "maxLength": 240 }, "identifier_count": { "type": "integer", "minimum": 1 }, "effective_from": { "type": "string", "format": "date" }, "effective_to": { "type": [ "string", "null" ], "format": "date" }, "recorded_at": { "$ref": "#/components/schemas/IsoDateTime" } } }, "CatalogEntityPage": { "type": "object", "additionalProperties": false, "required": [ "data", "meta" ], "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/CatalogEntitySummary" } }, "meta": { "$ref": "#/components/schemas/CursorMeta" } } }, "CatalogEntityIdentifier": { "type": "object", "additionalProperties": false, "required": [ "identifier", "namespace", "value", "issuer" ], "properties": { "identifier": { "$ref": "#/components/schemas/Uuid" }, "namespace": { "type": "string", "enum": [ "isrc", "iswc", "gtin", "catalog_number", "dsp_asset", "ddex_party", "society_party", "tenant_ref", "connector_ref" ] }, "value": { "type": "string", "minLength": 1, "maxLength": 320 }, "issuer": { "type": [ "string", "null" ], "maxLength": 160 } } }, "CatalogEntityDetail": { "type": "object", "additionalProperties": false, "required": [ "entity", "entity_type", "snapshot", "version", "source", "source_reference", "effective_from", "effective_to", "recorded_at", "metadata", "identifiers" ], "properties": { "entity": { "$ref": "#/components/schemas/Uuid" }, "entity_type": { "type": "string", "enum": [ "recording", "release", "work", "party" ] }, "snapshot": { "$ref": "#/components/schemas/Uuid" }, "version": { "type": "integer", "minimum": 1 }, "source": { "type": "string", "maxLength": 80 }, "source_reference": { "type": "string", "maxLength": 160 }, "effective_from": { "type": "string", "format": "date" }, "effective_to": { "type": [ "string", "null" ], "format": "date" }, "recorded_at": { "$ref": "#/components/schemas/IsoDateTime" }, "metadata": { "type": "object", "additionalProperties": true }, "identifiers": { "type": "array", "minItems": 1, "maxItems": 100, "items": { "$ref": "#/components/schemas/CatalogEntityIdentifier" } } } }, "CatalogEntityDetailResponse": { "type": "object", "additionalProperties": false, "required": [ "data" ], "properties": { "data": { "$ref": "#/components/schemas/CatalogEntityDetail" } } }, "CatalogDecisionOutcome": { "type": "string", "enum": [ "approved", "rejected", "unmatched" ] }, "CatalogDecisionReason": { "type": "string", "enum": [ "verified_exact", "reviewed_metadata", "conflicting_evidence", "insufficient_evidence", "no_match" ] }, "CatalogDecisionSummary": { "type": "object", "additionalProperties": false, "required": [ "decision", "candidate", "version", "outcome", "reason_code", "reviewed_at" ], "properties": { "decision": { "$ref": "#/components/schemas/Uuid" }, "candidate": { "$ref": "#/components/schemas/NullableUuid" }, "version": { "type": "integer", "minimum": 1 }, "outcome": { "$ref": "#/components/schemas/CatalogDecisionOutcome" }, "reason_code": { "$ref": "#/components/schemas/CatalogDecisionReason" }, "reviewed_at": { "$ref": "#/components/schemas/IsoDateTime" } } }, "CatalogBestCandidate": { "type": "object", "additionalProperties": false, "required": [ "candidate", "method", "confidence", "entity", "snapshot" ], "properties": { "candidate": { "$ref": "#/components/schemas/Uuid" }, "method": { "type": "string", "enum": [ "exact_identifier", "approved_crosswalk", "metadata_suggestion" ] }, "confidence": { "type": "string", "pattern": "^(?:0\\.[0-9]{6}|1\\.0{6})$" }, "entity": { "$ref": "#/components/schemas/Uuid" }, "snapshot": { "$ref": "#/components/schemas/Uuid" }, "ranking": { "$ref": "#/components/schemas/CatalogCandidateRanking" } } }, "CatalogReviewItem": { "type": "object", "additionalProperties": false, "required": [ "case", "source", "source_reference", "entity_type", "state", "candidate_count", "created_at" ], "properties": { "case": { "$ref": "#/components/schemas/Uuid" }, "source": { "type": "string", "maxLength": 80 }, "source_reference": { "type": "string", "maxLength": 160 }, "entity_type": { "type": "string", "enum": [ "recording", "release", "work", "party" ] }, "state": { "$ref": "#/components/schemas/CatalogReviewStateValue" }, "latest_decision": { "$ref": "#/components/schemas/CatalogDecisionSummary" }, "candidate_count": { "type": "integer", "minimum": 0 }, "best_candidate": { "$ref": "#/components/schemas/CatalogBestCandidate" }, "created_at": { "$ref": "#/components/schemas/IsoDateTime" } } }, "CatalogReviewPage": { "type": "object", "additionalProperties": false, "required": [ "data", "meta" ], "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/CatalogReviewItem" } }, "meta": { "$ref": "#/components/schemas/CursorMeta" } } }, "CatalogReviewStateMetrics": { "type": "object", "additionalProperties": false, "required": [ "total", "unreviewed", "held", "released" ], "properties": { "total": { "type": "integer", "minimum": 0 }, "unreviewed": { "type": "integer", "minimum": 0 }, "held": { "type": "integer", "minimum": 0 }, "released": { "type": "integer", "minimum": 0 } } }, "CatalogSuspenseMetrics": { "type": "object", "additionalProperties": false, "required": [ "total", "unreviewed", "rejected", "unmatched" ], "properties": { "total": { "type": "integer", "minimum": 0 }, "unreviewed": { "type": "integer", "minimum": 0 }, "rejected": { "type": "integer", "minimum": 0 }, "unmatched": { "type": "integer", "minimum": 0 } } }, "CatalogCandidateMetrics": { "type": "object", "additionalProperties": false, "required": [ "total", "approved_crosswalk", "exact_identifier", "metadata_suggestion" ], "properties": { "total": { "type": "integer", "minimum": 0 }, "approved_crosswalk": { "type": "integer", "minimum": 0 }, "exact_identifier": { "type": "integer", "minimum": 0 }, "metadata_suggestion": { "type": "integer", "minimum": 0 } } }, "CatalogQueueAgeMetrics": { "type": "object", "additionalProperties": false, "required": [ "oldest_unreviewed_at", "over_24_hours", "over_7_days" ], "properties": { "oldest_unreviewed_at": { "$ref": "#/components/schemas/NullableIsoDateTime" }, "over_24_hours": { "type": "integer", "minimum": 0 }, "over_7_days": { "type": "integer", "minimum": 0 } } }, "CatalogReviewMetrics": { "type": "object", "additionalProperties": false, "required": [ "cases", "suspense", "exact_approval_ready", "candidates", "queue_age" ], "properties": { "cases": { "$ref": "#/components/schemas/CatalogReviewStateMetrics" }, "suspense": { "$ref": "#/components/schemas/CatalogSuspenseMetrics" }, "exact_approval_ready": { "type": "integer", "minimum": 0 }, "candidates": { "$ref": "#/components/schemas/CatalogCandidateMetrics" }, "queue_age": { "$ref": "#/components/schemas/CatalogQueueAgeMetrics" } } }, "CatalogReviewMetricsResponse": { "type": "object", "additionalProperties": false, "required": [ "data" ], "properties": { "data": { "$ref": "#/components/schemas/CatalogReviewMetrics" } } }, "CatalogMatchDetail": { "type": "object", "additionalProperties": false, "required": [ "case", "source", "source_reference", "entity_type", "evidence", "state", "candidate_count", "created_at" ], "properties": { "case": { "$ref": "#/components/schemas/Uuid" }, "source": { "type": "string", "maxLength": 80 }, "source_reference": { "type": "string", "maxLength": 160 }, "entity_type": { "type": "string", "enum": [ "recording", "release", "work", "party" ] }, "evidence": { "type": "object", "additionalProperties": true }, "state": { "$ref": "#/components/schemas/CatalogReviewStateValue" }, "latest_decision": { "$ref": "#/components/schemas/CatalogDecisionSummary" }, "candidate_count": { "type": "integer", "minimum": 0 }, "related_disputes": { "type": "array", "items": { "$ref": "#/components/schemas/CatalogLinkedDispute" } }, "created_at": { "$ref": "#/components/schemas/IsoDateTime" } } }, "CatalogMatchDetailResponse": { "type": "object", "additionalProperties": false, "required": [ "data" ], "properties": { "data": { "$ref": "#/components/schemas/CatalogMatchDetail" } } }, "CatalogCandidateItem": { "type": "object", "additionalProperties": false, "required": [ "candidate", "method", "confidence", "evidence", "entity", "snapshot", "metadata", "effective_from", "effective_to", "created_at" ], "properties": { "candidate": { "$ref": "#/components/schemas/Uuid" }, "method": { "type": "string", "enum": [ "exact_identifier", "approved_crosswalk", "metadata_suggestion" ] }, "confidence": { "type": "string", "pattern": "^(?:0\\.[0-9]{6}|1\\.0{6})$" }, "ranking": { "$ref": "#/components/schemas/CatalogCandidateRanking" }, "evidence": { "type": "object", "additionalProperties": true }, "entity": { "$ref": "#/components/schemas/Uuid" }, "snapshot": { "$ref": "#/components/schemas/Uuid" }, "metadata": { "type": "object", "additionalProperties": true }, "comparison": { "type": "array", "maxItems": 50, "items": { "$ref": "#/components/schemas/CatalogCandidateComparison" } }, "effective_from": { "type": "string", "format": "date" }, "effective_to": { "type": [ "string", "null" ], "format": "date" }, "created_at": { "$ref": "#/components/schemas/IsoDateTime" } } }, "CatalogCandidatePage": { "type": "object", "additionalProperties": false, "required": [ "data", "meta" ], "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/CatalogCandidateItem" } }, "meta": { "$ref": "#/components/schemas/CursorMeta" } } }, "CatalogDecisionRequest": { "type": "object", "additionalProperties": false, "required": [ "outcome", "reason_code" ], "properties": { "candidate": { "$ref": "#/components/schemas/NullableUuid" }, "outcome": { "$ref": "#/components/schemas/CatalogDecisionOutcome" }, "reason_code": { "$ref": "#/components/schemas/CatalogDecisionReason" } } }, "CatalogDecisionResult": { "type": "object", "additionalProperties": false, "required": [ "case", "decision", "candidate", "outcome", "reason_code", "accounting_state", "replayed" ], "properties": { "case": { "$ref": "#/components/schemas/Uuid" }, "decision": { "$ref": "#/components/schemas/Uuid" }, "candidate": { "$ref": "#/components/schemas/NullableUuid" }, "outcome": { "$ref": "#/components/schemas/CatalogDecisionOutcome" }, "reason_code": { "$ref": "#/components/schemas/CatalogDecisionReason" }, "accounting_state": { "type": "string", "enum": [ "held", "released" ] }, "replayed": { "type": "boolean" } } }, "CatalogDecisionResponse": { "type": "object", "additionalProperties": false, "required": [ "data" ], "properties": { "data": { "$ref": "#/components/schemas/CatalogDecisionResult" } } }, "CatalogLinkedDispute": { "type": "object", "additionalProperties": false, "required": [ "link", "dispute", "category", "reason", "response_due_on", "linked_at" ], "properties": { "link": { "$ref": "#/components/schemas/Uuid" }, "dispute": { "$ref": "#/components/schemas/Uuid" }, "category": { "type": "string", "pattern": "^[a-z][a-z0-9_]{0,63}$" }, "reason": { "type": "string", "minLength": 1, "maxLength": 500 }, "response_due_on": { "type": "string", "format": "date" }, "linked_at": { "$ref": "#/components/schemas/IsoDateTime" } } }, "CatalogDisputeLinkRequest": { "type": "object", "additionalProperties": false, "required": [ "dispute", "reason" ], "properties": { "dispute": { "$ref": "#/components/schemas/Uuid" }, "reason": { "type": "string", "minLength": 1, "maxLength": 500 } } }, "CatalogDisputeLinkResult": { "type": "object", "additionalProperties": false, "required": [ "case", "dispute", "link", "replayed" ], "properties": { "case": { "$ref": "#/components/schemas/Uuid" }, "dispute": { "$ref": "#/components/schemas/Uuid" }, "link": { "$ref": "#/components/schemas/Uuid" }, "replayed": { "type": "boolean" } } }, "CatalogDisputeLinkResponse": { "type": "object", "additionalProperties": false, "required": [ "data" ], "properties": { "data": { "$ref": "#/components/schemas/CatalogDisputeLinkResult" } } }, "CatalogCandidateRanking": { "type": "object", "additionalProperties": false, "required": [ "method_priority", "confidence_order", "tie_breaker" ], "properties": { "method_priority": { "type": "integer", "minimum": 1, "maximum": 3 }, "confidence_order": { "type": "string", "const": "descending" }, "tie_breaker": { "type": "string", "const": "stable_candidate_reference" } } }, "CatalogCandidateComparison": { "type": "object", "additionalProperties": false, "required": [ "field", "status" ], "properties": { "field": { "type": "string", "minLength": 1, "maxLength": 160 }, "status": { "type": "string", "enum": [ "exact", "normalized", "different" ] } } }, "AnomalyCaseStatus": { "type": "string", "enum": [ "open", "triaged", "investigating", "resolution_pending", "resolved", "accepted_risk", "suppressed" ] }, "AnomalyHoldStatus": { "type": "string", "enum": [ "none", "active", "released" ] }, "AnomalyClass": { "type": "string", "enum": [ "file_schema", "reconciliation", "catalog_rights", "rate_market", "contract_allocation", "ledger_statement", "payout_identity", "operational" ] }, "AnomalySeverity": { "type": "string", "enum": [ "info", "warning", "error", "critical" ] }, "AnomalyConsequence": { "type": "string", "enum": [ "observe", "review", "block" ] }, "AnomalyComment": { "type": "object", "additionalProperties": false, "required": [ "comment_ref", "actor_ref", "actor_role", "body", "commented_at" ], "properties": { "comment_ref": { "$ref": "#/components/schemas/Uuid" }, "actor_ref": { "$ref": "#/components/schemas/Uuid" }, "actor_role": { "type": "string", "enum": [ "platform_operator", "tenant_owner", "finance_approver", "royalty_manager", "analyst" ] }, "body": { "type": "string", "minLength": 1, "maxLength": 2000 }, "commented_at": { "$ref": "#/components/schemas/IsoDateTime" } } }, "AnomalyCaseItem": { "type": "object", "additionalProperties": false, "required": [ "case_ref", "finding_ref", "status", "hold_status", "assigned_to", "version", "class", "severity", "consequence", "rule_code", "rule_version", "source_type", "source_ref", "subject_type", "subject_ref", "explanation", "detected_at", "opened_at", "suppression_expires_at" ], "properties": { "case_ref": { "$ref": "#/components/schemas/Uuid" }, "finding_ref": { "$ref": "#/components/schemas/Uuid" }, "status": { "$ref": "#/components/schemas/AnomalyCaseStatus" }, "hold_status": { "$ref": "#/components/schemas/AnomalyHoldStatus" }, "assigned_to": { "$ref": "#/components/schemas/NullableUuid" }, "version": { "type": "integer", "minimum": 1 }, "class": { "$ref": "#/components/schemas/AnomalyClass" }, "severity": { "$ref": "#/components/schemas/AnomalySeverity" }, "consequence": { "$ref": "#/components/schemas/AnomalyConsequence" }, "rule_code": { "type": "string", "minLength": 3, "maxLength": 120 }, "rule_version": { "type": "string", "minLength": 1, "maxLength": 64 }, "source_type": { "type": "string", "minLength": 2, "maxLength": 80 }, "source_ref": { "$ref": "#/components/schemas/Uuid" }, "subject_type": { "type": "string", "minLength": 2, "maxLength": 80 }, "subject_ref": { "$ref": "#/components/schemas/Uuid" }, "explanation": { "type": "string", "minLength": 1, "maxLength": 1000 }, "detected_at": { "$ref": "#/components/schemas/IsoDateTime" }, "opened_at": { "$ref": "#/components/schemas/IsoDateTime" }, "suppression_expires_at": { "$ref": "#/components/schemas/NullableIsoDateTime" }, "comments": { "type": "array", "maxItems": 10000, "items": { "$ref": "#/components/schemas/AnomalyComment" } }, "comments_truncated": { "type": "boolean" } } }, "AnomalyCasePage": { "type": "object", "additionalProperties": false, "required": [ "data", "meta" ], "properties": { "data": { "type": "array", "maxItems": 100, "items": { "$ref": "#/components/schemas/AnomalyCaseItem" } }, "meta": { "$ref": "#/components/schemas/CursorMeta" } } }, "AnomalyCaseDetailResponse": { "type": "object", "additionalProperties": false, "required": [ "data" ], "properties": { "data": { "$ref": "#/components/schemas/AnomalyCaseItem" } } }, "AnomalyCommentRequest": { "type": "object", "additionalProperties": false, "required": [ "body" ], "properties": { "body": { "type": "string", "minLength": 1, "maxLength": 2000 } } }, "AnomalyCountMap": { "type": "object", "additionalProperties": { "type": "integer", "minimum": 0 } }, "AnomalyMetrics": { "type": "object", "additionalProperties": false, "required": [ "cases_by_status", "cases_by_hold", "findings_by_class", "findings_by_severity", "active_cases", "oldest_active_at", "expired_suppressions", "observed_at" ], "properties": { "cases_by_status": { "$ref": "#/components/schemas/AnomalyCountMap" }, "cases_by_hold": { "$ref": "#/components/schemas/AnomalyCountMap" }, "findings_by_class": { "$ref": "#/components/schemas/AnomalyCountMap" }, "findings_by_severity": { "$ref": "#/components/schemas/AnomalyCountMap" }, "active_cases": { "type": "integer", "minimum": 0 }, "oldest_active_at": { "$ref": "#/components/schemas/NullableIsoDateTime" }, "expired_suppressions": { "type": "integer", "minimum": 0 }, "observed_at": { "$ref": "#/components/schemas/IsoDateTime" } } }, "AnomalyMetricsResponse": { "type": "object", "additionalProperties": false, "required": [ "data" ], "properties": { "data": { "$ref": "#/components/schemas/AnomalyMetrics" } } }, "AnomalyCommentResult": { "type": "object", "additionalProperties": false, "required": [ "case", "comment", "body", "commented_at" ], "properties": { "case": { "$ref": "#/components/schemas/Uuid" }, "comment": { "$ref": "#/components/schemas/Uuid" }, "body": { "type": "string", "minLength": 1, "maxLength": 2000 }, "commented_at": { "$ref": "#/components/schemas/IsoDateTime" } } }, "AnomalyCommentResponse": { "type": "object", "additionalProperties": false, "required": [ "data" ], "properties": { "data": { "$ref": "#/components/schemas/AnomalyCommentResult" } } }, "CatalogBulkExactDecisionRequest": { "type": "object", "additionalProperties": false, "required": [ "items" ], "properties": { "items": { "type": "array", "minItems": 1, "maxItems": 20, "items": { "type": "object", "additionalProperties": false, "required": [ "case", "candidate" ], "properties": { "case": { "$ref": "#/components/schemas/Uuid" }, "candidate": { "$ref": "#/components/schemas/Uuid" } } } } } }, "CatalogBulkExactDecisionItem": { "type": "object", "additionalProperties": false, "required": [ "case", "candidate", "decision", "accounting_state" ], "properties": { "case": { "$ref": "#/components/schemas/Uuid" }, "candidate": { "$ref": "#/components/schemas/Uuid" }, "decision": { "$ref": "#/components/schemas/Uuid" }, "accounting_state": { "type": "string", "const": "released" } } }, "CatalogBulkExactDecisionResponse": { "type": "object", "additionalProperties": false, "required": [ "data" ], "properties": { "data": { "type": "object", "additionalProperties": false, "required": [ "items", "replayed" ], "properties": { "items": { "type": "array", "minItems": 1, "maxItems": 20, "items": { "$ref": "#/components/schemas/CatalogBulkExactDecisionItem" } }, "replayed": { "type": "boolean" } } } } }, "PayoutExceptionSummary": { "type": "object", "additionalProperties": false, "required": [ "case", "command", "exception_type", "state", "queue_status", "attempts", "max_attempts", "error_code", "opened_at", "lookup_recheck_allowed" ], "properties": { "case": { "$ref": "#/components/schemas/Uuid" }, "command": { "$ref": "#/components/schemas/Uuid" }, "exception_type": { "type": "string", "enum": [ "ambiguous", "dead_lettered" ] }, "state": { "type": "string", "enum": [ "open", "resolved" ] }, "queue_status": { "type": "string", "enum": [ "pending", "processing", "ambiguous", "submitted", "failed", "dead_lettered" ] }, "attempts": { "type": "integer", "minimum": 0, "maximum": 50 }, "max_attempts": { "type": "integer", "minimum": 1, "maximum": 50 }, "error_code": { "type": "string", "pattern": "^[a-z][a-z0-9._:-]{1,119}$" }, "opened_at": { "$ref": "#/components/schemas/IsoDateTime" }, "lookup_recheck_allowed": { "type": "boolean" } } }, "PayoutExceptionPage": { "type": "object", "additionalProperties": false, "required": [ "data", "meta" ], "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/PayoutExceptionSummary" } }, "meta": { "$ref": "#/components/schemas/CursorMeta" } } }, "PayoutExceptionEvent": { "type": "object", "additionalProperties": false, "required": [ "event", "sequence", "type", "finding", "reason", "role", "occurred_at" ], "properties": { "event": { "$ref": "#/components/schemas/Uuid" }, "sequence": { "type": "integer", "minimum": 1 }, "type": { "type": "string", "enum": [ "investigation_recorded", "lookup_recheck_requested" ] }, "finding": { "type": "string", "enum": [ "provider_lookup_required", "monitor_only", "manual_provider_review", "configuration_fault", "escalate_provider", "lookup_recheck_approved" ] }, "reason": { "type": "string", "minLength": 1, "maxLength": 1000 }, "role": { "$ref": "#/components/schemas/TenantRole" }, "occurred_at": { "$ref": "#/components/schemas/IsoDateTime" } } }, "PayoutExceptionDetail": { "type": "object", "additionalProperties": false, "required": [ "case", "command", "exception_type", "state", "queue_status", "attempts", "max_attempts", "error_code", "opened_at", "lookup_recheck_allowed", "events" ], "properties": { "case": { "$ref": "#/components/schemas/Uuid" }, "command": { "$ref": "#/components/schemas/Uuid" }, "exception_type": { "type": "string", "enum": [ "ambiguous", "dead_lettered" ] }, "state": { "type": "string", "enum": [ "open", "resolved" ] }, "queue_status": { "type": "string", "enum": [ "pending", "processing", "ambiguous", "submitted", "failed", "dead_lettered" ] }, "attempts": { "type": "integer", "minimum": 0, "maximum": 50 }, "max_attempts": { "type": "integer", "minimum": 1, "maximum": 50 }, "error_code": { "type": "string", "pattern": "^[a-z][a-z0-9._:-]{1,119}$" }, "opened_at": { "$ref": "#/components/schemas/IsoDateTime" }, "lookup_recheck_allowed": { "type": "boolean" }, "events": { "type": "array", "items": { "$ref": "#/components/schemas/PayoutExceptionEvent" } } } }, "PayoutExceptionDetailResponse": { "type": "object", "additionalProperties": false, "required": [ "data" ], "properties": { "data": { "$ref": "#/components/schemas/PayoutExceptionDetail" } } }, "InvestigatePayoutExceptionRequest": { "type": "object", "additionalProperties": false, "required": [ "finding", "reason" ], "properties": { "finding": { "type": "string", "enum": [ "provider_lookup_required", "monitor_only", "manual_provider_review", "configuration_fault", "escalate_provider" ] }, "reason": { "type": "string", "minLength": 1, "maxLength": 1000 } } }, "RecheckPayoutExceptionRequest": { "type": "object", "additionalProperties": false, "required": [ "reason" ], "properties": { "reason": { "type": "string", "minLength": 1, "maxLength": 1000 } } }, "PayoutExceptionEventResponse": { "type": "object", "additionalProperties": false, "required": [ "data" ], "properties": { "data": { "$ref": "#/components/schemas/PayoutExceptionEvent" } } }, "PayoutLookupRecheck": { "type": "object", "additionalProperties": false, "required": [ "event", "sequence", "type", "finding", "reason", "role", "occurred_at", "queue_status", "next_action" ], "properties": { "event": { "$ref": "#/components/schemas/Uuid" }, "sequence": { "type": "integer", "minimum": 1 }, "type": { "type": "string", "const": "lookup_recheck_requested" }, "finding": { "type": "string", "const": "lookup_recheck_approved" }, "reason": { "type": "string", "minLength": 1, "maxLength": 1000 }, "role": { "$ref": "#/components/schemas/TenantRole" }, "occurred_at": { "$ref": "#/components/schemas/IsoDateTime" }, "queue_status": { "type": "string", "const": "ambiguous" }, "next_action": { "type": "string", "const": "provider_lookup" } } }, "PayoutLookupRecheckResponse": { "type": "object", "additionalProperties": false, "required": [ "data" ], "properties": { "data": { "$ref": "#/components/schemas/PayoutLookupRecheck" } } }, "PayoutAlertRoute": { "type": "object", "additionalProperties": false, "required": [ "ref", "channel", "destination_ref", "minimum_severity", "effective_at", "expires_at", "status", "approved_by", "reviewed_by", "retired_by", "retired_at" ], "properties": { "ref": { "$ref": "#/components/schemas/Uuid" }, "channel": { "type": "string", "enum": [ "pagerduty", "email_group", "webhook" ] }, "destination_ref": { "$ref": "#/components/schemas/Uuid" }, "minimum_severity": { "type": "string", "enum": [ "degraded", "critical" ] }, "effective_at": { "$ref": "#/components/schemas/IsoDateTime" }, "expires_at": { "oneOf": [ { "$ref": "#/components/schemas/IsoDateTime" }, { "type": "null" } ] }, "status": { "type": "string", "enum": [ "active", "retired" ] }, "approved_by": { "$ref": "#/components/schemas/Uuid" }, "reviewed_by": { "$ref": "#/components/schemas/Uuid" }, "retired_by": { "$ref": "#/components/schemas/NullableUuid" }, "retired_at": { "oneOf": [ { "$ref": "#/components/schemas/IsoDateTime" }, { "type": "null" } ] } } }, "PayoutAlertRouteResponse": { "type": "object", "additionalProperties": false, "required": [ "data" ], "properties": { "data": { "$ref": "#/components/schemas/PayoutAlertRoute" } } }, "PayoutAlertRoutePage": { "type": "object", "additionalProperties": false, "required": [ "data", "meta" ], "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/PayoutAlertRoute" } }, "meta": { "$ref": "#/components/schemas/CursorMeta" } } }, "PayoutAlertRouteProposal": { "type": "object", "additionalProperties": false, "required": [ "ref", "status", "channel", "destination_ref", "minimum_severity", "effective_at", "expires_at", "proposed_by", "proposed_at", "decided_by", "decided_at", "decision_reason" ], "properties": { "ref": { "$ref": "#/components/schemas/Uuid" }, "status": { "type": "string", "enum": [ "pending", "approved", "rejected" ] }, "channel": { "type": "string", "enum": [ "pagerduty", "email_group", "webhook" ] }, "destination_ref": { "$ref": "#/components/schemas/Uuid" }, "minimum_severity": { "type": "string", "enum": [ "degraded", "critical" ] }, "effective_at": { "$ref": "#/components/schemas/IsoDateTime" }, "expires_at": { "oneOf": [ { "$ref": "#/components/schemas/IsoDateTime" }, { "type": "null" } ] }, "proposed_by": { "$ref": "#/components/schemas/Uuid" }, "proposed_at": { "$ref": "#/components/schemas/IsoDateTime" }, "decided_by": { "$ref": "#/components/schemas/NullableUuid" }, "decided_at": { "oneOf": [ { "$ref": "#/components/schemas/IsoDateTime" }, { "type": "null" } ] }, "decision_reason": { "type": [ "string", "null" ], "minLength": 8, "maxLength": 500 } } }, "PayoutAlertRouteProposalResponse": { "type": "object", "additionalProperties": false, "required": [ "data" ], "properties": { "data": { "$ref": "#/components/schemas/PayoutAlertRouteProposal" } } }, "PayoutAlertRouteProposalPage": { "type": "object", "additionalProperties": false, "required": [ "data", "meta" ], "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/PayoutAlertRouteProposal" } }, "meta": { "$ref": "#/components/schemas/CursorMeta" } } }, "ProposePayoutAlertRouteRequest": { "type": "object", "additionalProperties": false, "required": [ "channel", "destination_ref", "minimum_severity", "effective_at" ], "properties": { "channel": { "type": "string", "enum": [ "pagerduty", "email_group", "webhook" ] }, "destination_ref": { "$ref": "#/components/schemas/Uuid" }, "minimum_severity": { "type": "string", "enum": [ "degraded", "critical" ] }, "effective_at": { "$ref": "#/components/schemas/IsoDateTime" }, "expires_at": { "oneOf": [ { "$ref": "#/components/schemas/IsoDateTime" }, { "type": "null" } ] } } }, "RejectPayoutAlertRouteProposalRequest": { "type": "object", "additionalProperties": false, "required": [ "reason" ], "properties": { "reason": { "type": "string", "minLength": 8, "maxLength": 500 } } }, "PayoutAlertRouteProposalCommandResult": { "type": "object", "additionalProperties": false, "required": [ "proposal", "replayed" ], "properties": { "proposal": { "$ref": "#/components/schemas/PayoutAlertRouteProposal" }, "replayed": { "type": "boolean" } } }, "PayoutAlertRouteProposalCommandResponse": { "type": "object", "additionalProperties": false, "required": [ "data" ], "properties": { "data": { "$ref": "#/components/schemas/PayoutAlertRouteProposalCommandResult" } } }, "PayoutAlertRouteApprovalResult": { "type": "object", "additionalProperties": false, "required": [ "proposal", "route", "replayed" ], "properties": { "proposal": { "$ref": "#/components/schemas/PayoutAlertRouteProposal" }, "route": { "$ref": "#/components/schemas/PayoutAlertRoute" }, "replayed": { "type": "boolean" } } }, "PayoutAlertRouteApprovalResponse": { "type": "object", "additionalProperties": false, "required": [ "data" ], "properties": { "data": { "$ref": "#/components/schemas/PayoutAlertRouteApprovalResult" } } }, "MoneyString": { "type": "string", "pattern": "^(?:0|[1-9][0-9]{0,25})(?:\\.[0-9]{1,12})?$" }, "DisputeStateValue": { "type": "string", "enum": [ "open", "rejected", "withdrawn", "upheld" ] }, "DisputeSummary": { "type": "object", "additionalProperties": false, "required": [ "dispute", "statement", "amount", "currency", "category", "state", "submitted_on", "response_due_on", "submitted_at", "evidence_item_count", "evidence_total_bytes" ], "properties": { "dispute": { "$ref": "#/components/schemas/Uuid" }, "statement": { "$ref": "#/components/schemas/Uuid" }, "amount": { "$ref": "#/components/schemas/MoneyString" }, "currency": { "type": "string", "pattern": "^[A-Z]{3}$" }, "category": { "type": "string", "pattern": "^[a-z][a-z0-9_]{0,63}$" }, "state": { "$ref": "#/components/schemas/DisputeStateValue" }, "submitted_on": { "type": "string", "format": "date" }, "response_due_on": { "type": "string", "format": "date" }, "submitted_at": { "$ref": "#/components/schemas/IsoDateTime" }, "evidence_item_count": { "type": "integer", "minimum": 1, "maximum": 20 }, "evidence_total_bytes": { "type": "integer", "minimum": 1, "maximum": 524288000 } } }, "DisputePage": { "type": "object", "additionalProperties": false, "required": [ "data", "meta" ], "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/DisputeSummary" } }, "meta": { "$ref": "#/components/schemas/CursorMeta" } } }, "DisputeEvidenceItem": { "type": "object", "additionalProperties": false, "required": [ "item", "sequence", "label", "bytes", "media_type" ], "properties": { "item": { "$ref": "#/components/schemas/Uuid" }, "sequence": { "type": "integer", "minimum": 1, "maximum": 20 }, "label": { "type": "string", "minLength": 1, "maxLength": 160 }, "bytes": { "type": "integer", "minimum": 1, "maximum": 52428800 }, "media_type": { "type": "string", "maxLength": 255 } } }, "GrantedDisputeEvidenceAccess": { "type": "object", "additionalProperties": false, "required": [ "access", "expires_at", "download_url" ], "properties": { "access": { "$ref": "#/components/schemas/Uuid" }, "expires_at": { "$ref": "#/components/schemas/IsoDateTime" }, "download_url": { "type": "string", "format": "uri", "maxLength": 4096 } } }, "GrantedDisputeEvidenceAccessResponse": { "type": "object", "additionalProperties": false, "required": [ "data" ], "properties": { "data": { "$ref": "#/components/schemas/GrantedDisputeEvidenceAccess" } } }, "DisputeEvidence": { "type": "object", "additionalProperties": false, "required": [ "manifest", "item_count", "total_bytes", "approved_at", "items" ], "properties": { "manifest": { "$ref": "#/components/schemas/Uuid" }, "item_count": { "type": "integer", "minimum": 1, "maximum": 20 }, "total_bytes": { "type": "integer", "minimum": 1, "maximum": 524288000 }, "approved_at": { "$ref": "#/components/schemas/IsoDateTime" }, "items": { "type": "array", "minItems": 1, "maxItems": 20, "items": { "$ref": "#/components/schemas/DisputeEvidenceItem" } } } }, "DisputeEvent": { "type": "object", "additionalProperties": false, "required": [ "event", "sequence", "type", "occurred_at" ], "properties": { "event": { "$ref": "#/components/schemas/Uuid" }, "sequence": { "type": "integer", "minimum": 1 }, "type": { "type": "string", "enum": [ "submitted", "acknowledged", "assigned", "investigating", "proposed", "withdrawn", "rejected", "upheld", "escalated", "reopened" ] }, "occurred_at": { "$ref": "#/components/schemas/IsoDateTime" } } }, "DisputeOutcome": { "type": "object", "additionalProperties": false, "required": [ "outcome", "state", "reason", "decided_on", "decided_at" ], "properties": { "outcome": { "$ref": "#/components/schemas/Uuid" }, "state": { "type": "string", "enum": [ "rejected", "withdrawn", "upheld" ] }, "reason": { "type": "string", "minLength": 1, "maxLength": 1000 }, "correction": { "$ref": "#/components/schemas/Uuid" }, "replacement_statement": { "$ref": "#/components/schemas/Uuid" }, "decided_on": { "type": "string", "format": "date" }, "decided_at": { "$ref": "#/components/schemas/IsoDateTime" } } }, "DisputeAcknowledgementSummary": { "type": "object", "additionalProperties": false, "required": [ "acknowledgement", "note", "acknowledged_at" ], "properties": { "acknowledgement": { "$ref": "#/components/schemas/Uuid" }, "note": { "type": "string", "minLength": 1, "maxLength": 1000 }, "acknowledged_at": { "$ref": "#/components/schemas/IsoDateTime" } } }, "DisputeAssignment": { "type": "object", "additionalProperties": false, "required": [ "assignment", "sequence", "assignee", "reason", "assigned_at" ], "properties": { "assignment": { "$ref": "#/components/schemas/Uuid" }, "sequence": { "type": "integer", "minimum": 1 }, "assignee": { "$ref": "#/components/schemas/Uuid" }, "reason": { "type": "string", "minLength": 1, "maxLength": 1000 }, "assigned_at": { "$ref": "#/components/schemas/IsoDateTime" } } }, "DisputeInvestigation": { "type": "object", "additionalProperties": false, "required": [ "investigation", "assignment", "reason", "started_at" ], "properties": { "investigation": { "$ref": "#/components/schemas/Uuid" }, "assignment": { "$ref": "#/components/schemas/Uuid" }, "reason": { "type": "string", "minLength": 1, "maxLength": 1000 }, "started_at": { "$ref": "#/components/schemas/IsoDateTime" } } }, "DisputeProposal": { "type": "object", "additionalProperties": false, "required": [ "proposal", "investigation", "assignment", "recommendation", "reason", "proposed_at" ], "properties": { "proposal": { "$ref": "#/components/schemas/Uuid" }, "investigation": { "$ref": "#/components/schemas/Uuid" }, "assignment": { "$ref": "#/components/schemas/Uuid" }, "recommendation": { "type": "string", "enum": [ "rejected", "withdrawn", "upheld" ] }, "reason": { "type": "string", "minLength": 1, "maxLength": 1000 }, "proposed_at": { "$ref": "#/components/schemas/IsoDateTime" } } }, "DisputeEscalation": { "type": "object", "additionalProperties": false, "required": [ "escalation", "proposal", "assignment", "target_role", "reason", "response_due_on", "escalated_at" ], "properties": { "escalation": { "$ref": "#/components/schemas/Uuid" }, "proposal": { "$ref": "#/components/schemas/Uuid" }, "assignment": { "$ref": "#/components/schemas/Uuid" }, "target_role": { "type": "string", "enum": [ "finance_approver", "tenant_owner" ] }, "reason": { "type": "string", "minLength": 1, "maxLength": 1000 }, "response_due_on": { "type": "string", "format": "date" }, "escalated_at": { "$ref": "#/components/schemas/IsoDateTime" } } }, "DisputeNote": { "type": "object", "additionalProperties": false, "required": [ "note", "sequence", "body", "recorded_at" ], "properties": { "note": { "$ref": "#/components/schemas/Uuid" }, "sequence": { "type": "integer", "minimum": 1 }, "body": { "type": "string", "minLength": 1, "maxLength": 4000 }, "recorded_at": { "$ref": "#/components/schemas/IsoDateTime" } } }, "DisputeNotePage": { "type": "object", "additionalProperties": false, "required": [ "data", "meta" ], "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/DisputeNote" } }, "meta": { "$ref": "#/components/schemas/CursorMeta" } } }, "DisputeDetail": { "type": "object", "additionalProperties": false, "required": [ "dispute", "statement", "amount", "currency", "category", "state", "submitted_on", "response_due_on", "submitted_at", "evidence_item_count", "evidence_total_bytes", "reason", "evidence", "events" ], "properties": { "dispute": { "$ref": "#/components/schemas/Uuid" }, "statement": { "$ref": "#/components/schemas/Uuid" }, "amount": { "$ref": "#/components/schemas/MoneyString" }, "currency": { "type": "string", "pattern": "^[A-Z]{3}$" }, "category": { "type": "string", "pattern": "^[a-z][a-z0-9_]{0,63}$" }, "state": { "$ref": "#/components/schemas/DisputeStateValue" }, "submitted_on": { "type": "string", "format": "date" }, "response_due_on": { "type": "string", "format": "date" }, "submitted_at": { "$ref": "#/components/schemas/IsoDateTime" }, "evidence_item_count": { "type": "integer", "minimum": 1, "maximum": 20 }, "evidence_total_bytes": { "type": "integer", "minimum": 1, "maximum": 524288000 }, "reason": { "type": "string", "minLength": 1, "maxLength": 1000 }, "evidence": { "$ref": "#/components/schemas/DisputeEvidence" }, "events": { "type": "array", "minItems": 1, "items": { "$ref": "#/components/schemas/DisputeEvent" } }, "outcome": { "$ref": "#/components/schemas/DisputeOutcome" }, "acknowledgement": { "$ref": "#/components/schemas/DisputeAcknowledgementSummary" }, "assignments": { "type": "array", "minItems": 1, "items": { "$ref": "#/components/schemas/DisputeAssignment" } }, "current_assignment": { "$ref": "#/components/schemas/DisputeAssignment" }, "investigation": { "$ref": "#/components/schemas/DisputeInvestigation" }, "proposal": { "$ref": "#/components/schemas/DisputeProposal" }, "escalation": { "$ref": "#/components/schemas/DisputeEscalation" } } }, "DisputeDetailResponse": { "type": "object", "additionalProperties": false, "required": [ "data" ], "properties": { "data": { "$ref": "#/components/schemas/DisputeDetail" } } }, "SubmitDisputeRequest": { "type": "object", "additionalProperties": false, "required": [ "statement", "amount", "category", "reason", "evidence_manifest_hash", "submitted_on", "response_due_on" ], "properties": { "statement": { "$ref": "#/components/schemas/Uuid" }, "amount": { "$ref": "#/components/schemas/MoneyString" }, "category": { "type": "string", "pattern": "^[a-z][a-z0-9_]{0,63}$" }, "reason": { "type": "string", "minLength": 1, "maxLength": 1000 }, "evidence_manifest_hash": { "type": "string", "pattern": "^[a-f0-9]{64}$" }, "submitted_on": { "type": "string", "format": "date" }, "response_due_on": { "type": "string", "format": "date" } } }, "UploadDisputeEvidenceRequest": { "type": "object", "additionalProperties": false, "required": [ "file", "media_type", "label" ], "properties": { "file": { "type": "string", "format": "binary" }, "media_type": { "type": "string", "enum": [ "application/pdf", "image/jpeg", "image/png" ] }, "label": { "type": "string", "minLength": 1, "maxLength": 160 } } }, "UploadedDisputeEvidence": { "type": "object", "additionalProperties": false, "required": [ "evidence_manifest", "evidence_manifest_hash", "item_count", "total_bytes", "media_type" ], "properties": { "evidence_manifest": { "$ref": "#/components/schemas/Uuid" }, "evidence_manifest_hash": { "type": "string", "pattern": "^[a-f0-9]{64}$" }, "item_count": { "type": "integer", "const": 1 }, "total_bytes": { "type": "integer", "minimum": 1, "maximum": 52428800 }, "media_type": { "type": "string", "enum": [ "application/pdf", "image/jpeg", "image/png" ] } } }, "UploadedDisputeEvidenceResponse": { "type": "object", "additionalProperties": false, "required": [ "data" ], "properties": { "data": { "$ref": "#/components/schemas/UploadedDisputeEvidence" } } }, "AcknowledgeDisputeRequest": { "type": "object", "additionalProperties": false, "required": [ "note" ], "properties": { "note": { "type": "string", "minLength": 1, "maxLength": 1000 } } }, "AcknowledgedDispute": { "type": "object", "additionalProperties": false, "required": [ "dispute", "acknowledgement", "note", "state", "acknowledged_at" ], "properties": { "dispute": { "$ref": "#/components/schemas/Uuid" }, "acknowledgement": { "$ref": "#/components/schemas/Uuid" }, "note": { "type": "string", "minLength": 1, "maxLength": 1000 }, "state": { "type": "string", "const": "acknowledged" }, "acknowledged_at": { "$ref": "#/components/schemas/IsoDateTime" } } }, "AcknowledgedDisputeResponse": { "type": "object", "additionalProperties": false, "required": [ "data" ], "properties": { "data": { "$ref": "#/components/schemas/AcknowledgedDispute" } } }, "AssignDisputeRequest": { "type": "object", "additionalProperties": false, "required": [ "assignee", "reason" ], "properties": { "assignee": { "$ref": "#/components/schemas/Uuid" }, "reason": { "type": "string", "minLength": 1, "maxLength": 1000 } } }, "AssignedDispute": { "type": "object", "additionalProperties": false, "required": [ "dispute", "assignment", "assignee", "sequence", "reason", "state", "assigned_at" ], "properties": { "dispute": { "$ref": "#/components/schemas/Uuid" }, "assignment": { "$ref": "#/components/schemas/Uuid" }, "assignee": { "$ref": "#/components/schemas/Uuid" }, "sequence": { "type": "integer", "minimum": 1 }, "reason": { "type": "string", "minLength": 1, "maxLength": 1000 }, "state": { "type": "string", "const": "assigned" }, "assigned_at": { "$ref": "#/components/schemas/IsoDateTime" } } }, "AssignedDisputeResponse": { "type": "object", "additionalProperties": false, "required": [ "data" ], "properties": { "data": { "$ref": "#/components/schemas/AssignedDispute" } } }, "InvestigateDisputeRequest": { "type": "object", "additionalProperties": false, "required": [ "reason" ], "properties": { "reason": { "type": "string", "minLength": 1, "maxLength": 1000 } } }, "InvestigatingDispute": { "type": "object", "additionalProperties": false, "required": [ "dispute", "investigation", "assignment", "reason", "state", "started_at" ], "properties": { "dispute": { "$ref": "#/components/schemas/Uuid" }, "investigation": { "$ref": "#/components/schemas/Uuid" }, "assignment": { "$ref": "#/components/schemas/Uuid" }, "reason": { "type": "string", "minLength": 1, "maxLength": 1000 }, "state": { "type": "string", "const": "investigating" }, "started_at": { "$ref": "#/components/schemas/IsoDateTime" } } }, "InvestigatingDisputeResponse": { "type": "object", "additionalProperties": false, "required": [ "data" ], "properties": { "data": { "$ref": "#/components/schemas/InvestigatingDispute" } } }, "ProposeDisputeRequest": { "type": "object", "additionalProperties": false, "required": [ "recommendation", "reason" ], "properties": { "recommendation": { "type": "string", "enum": [ "rejected", "withdrawn", "upheld" ] }, "reason": { "type": "string", "minLength": 1, "maxLength": 1000 } } }, "ProposedDispute": { "type": "object", "additionalProperties": false, "required": [ "dispute", "proposal", "investigation", "assignment", "recommendation", "reason", "state", "proposed_at" ], "properties": { "dispute": { "$ref": "#/components/schemas/Uuid" }, "proposal": { "$ref": "#/components/schemas/Uuid" }, "investigation": { "$ref": "#/components/schemas/Uuid" }, "assignment": { "$ref": "#/components/schemas/Uuid" }, "recommendation": { "type": "string", "enum": [ "rejected", "withdrawn", "upheld" ] }, "reason": { "type": "string", "minLength": 1, "maxLength": 1000 }, "state": { "type": "string", "const": "proposed" }, "proposed_at": { "$ref": "#/components/schemas/IsoDateTime" } } }, "ProposedDisputeResponse": { "type": "object", "additionalProperties": false, "required": [ "data" ], "properties": { "data": { "$ref": "#/components/schemas/ProposedDispute" } } }, "EscalateDisputeRequest": { "type": "object", "additionalProperties": false, "required": [ "target_role", "reason", "response_due_on" ], "properties": { "target_role": { "type": "string", "enum": [ "finance_approver", "tenant_owner" ] }, "reason": { "type": "string", "minLength": 1, "maxLength": 1000 }, "response_due_on": { "type": "string", "format": "date" } } }, "EscalatedDispute": { "type": "object", "additionalProperties": false, "required": [ "dispute", "escalation", "proposal", "assignment", "target_role", "reason", "response_due_on", "state", "escalated_at" ], "properties": { "dispute": { "$ref": "#/components/schemas/Uuid" }, "escalation": { "$ref": "#/components/schemas/Uuid" }, "proposal": { "$ref": "#/components/schemas/Uuid" }, "assignment": { "$ref": "#/components/schemas/Uuid" }, "target_role": { "type": "string", "enum": [ "finance_approver", "tenant_owner" ] }, "reason": { "type": "string", "minLength": 1, "maxLength": 1000 }, "response_due_on": { "type": "string", "format": "date" }, "state": { "type": "string", "const": "escalated" }, "escalated_at": { "$ref": "#/components/schemas/IsoDateTime" } } }, "EscalatedDisputeResponse": { "type": "object", "additionalProperties": false, "required": [ "data" ], "properties": { "data": { "$ref": "#/components/schemas/EscalatedDispute" } } }, "RecordDisputeNoteRequest": { "type": "object", "additionalProperties": false, "required": [ "body" ], "properties": { "body": { "type": "string", "minLength": 1, "maxLength": 4000 } } }, "RecordedDisputeNote": { "type": "object", "additionalProperties": false, "required": [ "dispute", "note", "sequence", "body", "recorded_at" ], "properties": { "dispute": { "$ref": "#/components/schemas/Uuid" }, "note": { "$ref": "#/components/schemas/Uuid" }, "sequence": { "type": "integer", "minimum": 1 }, "body": { "type": "string", "minLength": 1, "maxLength": 4000 }, "recorded_at": { "$ref": "#/components/schemas/IsoDateTime" } } }, "RecordedDisputeNoteResponse": { "type": "object", "additionalProperties": false, "required": [ "data" ], "properties": { "data": { "$ref": "#/components/schemas/RecordedDisputeNote" } } }, "RecordDisputeCommunicationRequest": { "type": "object", "additionalProperties": false, "required": [ "direction", "channel", "external_party_ref", "external_message_ref", "subject", "body", "occurred_at" ], "properties": { "direction": { "type": "string", "enum": [ "inbound", "outbound" ] }, "channel": { "type": "string", "enum": [ "email", "letter", "phone", "portal", "other" ] }, "external_party_ref": { "type": "string", "minLength": 1, "maxLength": 160 }, "external_message_ref": { "type": "string", "pattern": "^[A-Za-z0-9._:@/-]{8,160}$" }, "subject": { "type": "string", "minLength": 1, "maxLength": 240 }, "body": { "type": "string", "minLength": 1, "maxLength": 4000 }, "occurred_at": { "type": "string", "format": "date-time" } } }, "RecordedDisputeCommunication": { "type": "object", "additionalProperties": false, "required": [ "dispute", "communication", "sequence", "direction", "channel", "occurred_at", "recorded_at" ], "properties": { "dispute": { "$ref": "#/components/schemas/Uuid" }, "communication": { "$ref": "#/components/schemas/Uuid" }, "sequence": { "type": "integer", "minimum": 1 }, "direction": { "type": "string", "enum": [ "inbound", "outbound" ] }, "channel": { "type": "string", "enum": [ "email", "letter", "phone", "portal", "other" ] }, "occurred_at": { "$ref": "#/components/schemas/IsoDateTime" }, "recorded_at": { "$ref": "#/components/schemas/IsoDateTime" } } }, "RecordedDisputeCommunicationResponse": { "type": "object", "additionalProperties": false, "required": [ "data" ], "properties": { "data": { "$ref": "#/components/schemas/RecordedDisputeCommunication" } } }, "ReopenDisputeRequest": { "type": "object", "additionalProperties": false, "required": [ "reason", "evidence_manifest_hash", "submitted_on", "response_due_on" ], "properties": { "reason": { "type": "string", "minLength": 1, "maxLength": 1000 }, "evidence_manifest_hash": { "type": "string", "pattern": "^[a-f0-9]{64}$" }, "submitted_on": { "type": "string", "format": "date" }, "response_due_on": { "type": "string", "format": "date" } } }, "ReopenedDispute": { "type": "object", "additionalProperties": false, "required": [ "dispute", "reopen", "child_dispute", "state", "submitted_on", "response_due_on" ], "properties": { "dispute": { "$ref": "#/components/schemas/Uuid" }, "reopen": { "$ref": "#/components/schemas/Uuid" }, "child_dispute": { "$ref": "#/components/schemas/Uuid" }, "state": { "type": "string", "const": "reopened" }, "submitted_on": { "type": "string", "format": "date" }, "response_due_on": { "type": "string", "format": "date" } } }, "ReopenedDisputeResponse": { "type": "object", "additionalProperties": false, "required": [ "data" ], "properties": { "data": { "$ref": "#/components/schemas/ReopenedDispute" } } }, "SubmittedDispute": { "type": "object", "additionalProperties": false, "required": [ "dispute", "amount", "currency", "category", "submitted_on", "response_due_on", "state" ], "properties": { "dispute": { "$ref": "#/components/schemas/Uuid" }, "amount": { "$ref": "#/components/schemas/MoneyString" }, "currency": { "type": "string", "pattern": "^[A-Z]{3}$" }, "category": { "type": "string", "pattern": "^[a-z][a-z0-9_]{0,63}$" }, "submitted_on": { "type": "string", "format": "date" }, "response_due_on": { "type": "string", "format": "date" }, "state": { "type": "string", "const": "submitted" } } }, "SubmittedDisputeResponse": { "type": "object", "additionalProperties": false, "required": [ "data" ], "properties": { "data": { "$ref": "#/components/schemas/SubmittedDispute" } } }, "ReleaseDisputeRequest": { "type": "object", "additionalProperties": false, "required": [ "disposition", "reason", "resolved_on" ], "properties": { "disposition": { "type": "string", "enum": [ "rejected", "withdrawn" ] }, "reason": { "type": "string", "minLength": 1, "maxLength": 1000 }, "resolved_on": { "type": "string", "format": "date" } } }, "ReleasedDispute": { "type": "object", "additionalProperties": false, "required": [ "dispute", "resolution", "state", "resolved_on" ], "properties": { "dispute": { "$ref": "#/components/schemas/Uuid" }, "resolution": { "$ref": "#/components/schemas/Uuid" }, "state": { "type": "string", "enum": [ "rejected", "withdrawn" ] }, "resolved_on": { "type": "string", "format": "date" } } }, "ReleasedDisputeResponse": { "type": "object", "additionalProperties": false, "required": [ "data" ], "properties": { "data": { "$ref": "#/components/schemas/ReleasedDispute" } } }, "UpholdDisputeRequest": { "type": "object", "additionalProperties": false, "required": [ "correction", "reason", "upheld_on" ], "properties": { "correction": { "$ref": "#/components/schemas/Uuid" }, "reason": { "type": "string", "minLength": 1, "maxLength": 1000 }, "upheld_on": { "type": "string", "format": "date" } } }, "UpheldDispute": { "type": "object", "additionalProperties": false, "required": [ "dispute", "uphold", "correction", "state", "upheld_on" ], "properties": { "dispute": { "$ref": "#/components/schemas/Uuid" }, "uphold": { "$ref": "#/components/schemas/Uuid" }, "correction": { "$ref": "#/components/schemas/Uuid" }, "state": { "type": "string", "const": "upheld" }, "upheld_on": { "type": "string", "format": "date" } } }, "UpheldDisputeResponse": { "type": "object", "additionalProperties": false, "required": [ "data" ], "properties": { "data": { "$ref": "#/components/schemas/UpheldDispute" } } }, "PublishedCoverageCount": { "type": "object", "additionalProperties": false, "required": [ "covered_rows", "total_rows" ], "properties": { "covered_rows": { "type": "integer", "minimum": 0 }, "total_rows": { "type": "integer", "minimum": 0 } } }, "PublishedAnalyticsTotals": { "type": "object", "additionalProperties": false, "required": [ "units", "duration_seconds", "gross_revenue", "deductions", "taxes", "costs", "net_revenue" ], "properties": { "units": { "$ref": "#/components/schemas/SignedCanonicalDecimal" }, "duration_seconds": { "$ref": "#/components/schemas/SignedCanonicalDecimal" }, "gross_revenue": { "$ref": "#/components/schemas/SignedCanonicalDecimal" }, "deductions": { "$ref": "#/components/schemas/SignedCanonicalDecimal" }, "taxes": { "$ref": "#/components/schemas/SignedCanonicalDecimal" }, "costs": { "$ref": "#/components/schemas/SignedCanonicalDecimal" }, "net_revenue": { "$ref": "#/components/schemas/SignedCanonicalDecimal" } } }, "PublishedAnalyticsCoverage": { "type": "object", "additionalProperties": false, "required": [ "units", "duration_seconds", "gross_revenue", "deductions", "taxes", "costs", "net_revenue", "territory", "subscription_plan" ], "properties": { "units": { "$ref": "#/components/schemas/PublishedCoverageCount" }, "duration_seconds": { "$ref": "#/components/schemas/PublishedCoverageCount" }, "gross_revenue": { "$ref": "#/components/schemas/PublishedCoverageCount" }, "deductions": { "$ref": "#/components/schemas/PublishedCoverageCount" }, "taxes": { "$ref": "#/components/schemas/PublishedCoverageCount" }, "costs": { "$ref": "#/components/schemas/PublishedCoverageCount" }, "net_revenue": { "$ref": "#/components/schemas/PublishedCoverageCount" }, "territory": { "$ref": "#/components/schemas/PublishedCoverageCount" }, "subscription_plan": { "$ref": "#/components/schemas/PublishedCoverageCount" } } }, "PublishedAnalyticsCommonFilters": { "type": "object", "additionalProperties": false, "required": [ "currency", "currency_basis", "import", "period_start", "period_end" ], "properties": { "currency": { "$ref": "#/components/schemas/CurrencyCode" }, "currency_basis": { "$ref": "#/components/schemas/CurrencyBasis" }, "import": { "$ref": "#/components/schemas/NullableUuid" }, "period_start": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/ReportMonth" } ] }, "period_end": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/ReportMonth" } ] } } }, "PublishedAnalyticsSummary": { "type": "object", "additionalProperties": false, "required": [ "currency", "currency_basis", "rows", "imports", "generations", "published_at", "totals", "coverage" ], "properties": { "currency": { "$ref": "#/components/schemas/CurrencyCode" }, "currency_basis": { "$ref": "#/components/schemas/CurrencyBasis" }, "rows": { "type": "integer", "minimum": 0 }, "imports": { "type": "integer", "minimum": 0 }, "generations": { "type": "integer", "minimum": 0 }, "published_at": { "$ref": "#/components/schemas/NullableIsoDateTime" }, "totals": { "$ref": "#/components/schemas/PublishedAnalyticsTotals" }, "coverage": { "$ref": "#/components/schemas/PublishedAnalyticsCoverage" } } }, "PublishedAnalyticsSummaryResponse": { "type": "object", "additionalProperties": false, "required": [ "data", "meta" ], "properties": { "data": { "$ref": "#/components/schemas/PublishedAnalyticsSummary" }, "meta": { "type": "object", "additionalProperties": false, "required": [ "scope", "filters" ], "properties": { "scope": { "type": "string", "const": "published_generation" }, "filters": { "$ref": "#/components/schemas/PublishedAnalyticsCommonFilters" } } } } }, "PublishedAnalyticsFilterOption": { "type": "object", "additionalProperties": false, "required": [ "key", "state", "rows", "imports", "generations" ], "properties": { "key": { "type": [ "string", "null" ], "maxLength": 160 }, "state": { "$ref": "#/components/schemas/CommercialValueState" }, "rows": { "type": "integer", "minimum": 1 }, "imports": { "type": "integer", "minimum": 1 }, "generations": { "type": "integer", "minimum": 1 } } }, "PublishedAnalyticsFilterDimension": { "type": "object", "additionalProperties": false, "required": [ "name", "options", "suppressed_rows" ], "properties": { "name": { "$ref": "#/components/schemas/CommercialDimension" }, "options": { "type": "array", "items": { "$ref": "#/components/schemas/PublishedAnalyticsFilterOption" } }, "suppressed_rows": { "type": "integer", "minimum": 0 } } }, "PublishedAnalyticsFilterOptionsFilters": { "type": "object", "additionalProperties": false, "required": [ "currency", "currency_basis", "import", "period_start", "period_end", "basis", "taxonomy" ], "properties": { "currency": { "$ref": "#/components/schemas/CurrencyCode" }, "currency_basis": { "$ref": "#/components/schemas/CurrencyBasis" }, "import": { "$ref": "#/components/schemas/NullableUuid" }, "period_start": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/ReportMonth" } ] }, "period_end": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/ReportMonth" } ] }, "basis": { "$ref": "#/components/schemas/RateBasis" }, "taxonomy": { "$ref": "#/components/schemas/NullableUuid" } } }, "PublishedAnalyticsFilterOptionsResponse": { "type": "object", "additionalProperties": false, "required": [ "data", "meta" ], "properties": { "data": { "type": "array", "minItems": 11, "maxItems": 11, "items": { "$ref": "#/components/schemas/PublishedAnalyticsFilterDimension" } }, "meta": { "type": "object", "additionalProperties": false, "required": [ "scope", "privacy", "filters" ], "properties": { "scope": { "type": "string", "const": "published_generation" }, "privacy": { "type": "object", "additionalProperties": false, "required": [ "minimum_rows", "suppression" ], "properties": { "minimum_rows": { "type": "integer", "minimum": 2, "maximum": 10000 }, "suppression": { "type": "string", "const": "aggregate_only" } } }, "filters": { "$ref": "#/components/schemas/PublishedAnalyticsFilterOptionsFilters" } } } } }, "PublishedAnalyticsReadinessCount": { "type": "object", "additionalProperties": false, "required": [ "rows", "imports", "generations", "published_at" ], "properties": { "rows": { "type": "integer", "minimum": 0 }, "imports": { "type": "integer", "minimum": 0 }, "generations": { "type": "integer", "minimum": 0 }, "published_at": { "$ref": "#/components/schemas/NullableIsoDateTime" } } }, "PublishedAnalyticsReadiness": { "type": "object", "additionalProperties": false, "required": [ "status", "stale", "published_at", "publications", "market", "rates" ], "properties": { "status": { "type": "string", "enum": [ "empty", "degraded", "stale", "ready" ] }, "stale": { "type": "boolean" }, "published_at": { "$ref": "#/components/schemas/NullableIsoDateTime" }, "publications": { "$ref": "#/components/schemas/PublishedAnalyticsReadinessCount" }, "market": { "$ref": "#/components/schemas/PublishedAnalyticsReadinessCount" }, "rates": { "$ref": "#/components/schemas/PublishedAnalyticsReadinessCount" } } }, "PublishedAnalyticsReadinessResponse": { "type": "object", "additionalProperties": false, "required": [ "data", "meta" ], "properties": { "data": { "$ref": "#/components/schemas/PublishedAnalyticsReadiness" }, "meta": { "type": "object", "additionalProperties": false, "required": [ "scope", "stale_after_seconds" ], "properties": { "scope": { "type": "string", "const": "published_generation" }, "stale_after_seconds": { "type": "integer", "minimum": 300, "maximum": 31536000 } } } } }, "PublishedRateDimension": { "type": "object", "additionalProperties": false, "required": [ "name", "key", "state" ], "properties": { "name": { "$ref": "#/components/schemas/CommercialDimension" }, "key": { "type": [ "string", "null" ], "maxLength": 160 }, "state": { "$ref": "#/components/schemas/CommercialValueState" } } }, "PublishedAnalyticsBreakdownAuthority": { "type": "object", "additionalProperties": false, "required": [ "currency", "currency_basis", "rate_basis", "taxonomy" ], "properties": { "currency": { "$ref": "#/components/schemas/CurrencyCode" }, "currency_basis": { "$ref": "#/components/schemas/CurrencyBasis" }, "rate_basis": { "$ref": "#/components/schemas/RateBasis" }, "taxonomy": { "$ref": "#/components/schemas/NullableUuid" } } }, "PublishedAnalyticsBreakdownSide": { "type": "object", "additionalProperties": false, "required": [ "eligible_rows", "eligible_units", "eligible_revenue" ], "properties": { "eligible_rows": { "type": "integer", "minimum": 0 }, "eligible_units": { "$ref": "#/components/schemas/SignedCanonicalDecimal" }, "eligible_revenue": { "$ref": "#/components/schemas/SignedCanonicalDecimal" } } }, "PublishedAnalyticsBreakdownCoverage": { "type": "object", "additionalProperties": false, "required": [ "territory", "subscription_plan" ], "properties": { "territory": { "$ref": "#/components/schemas/PublishedCoverageCount" }, "subscription_plan": { "$ref": "#/components/schemas/PublishedCoverageCount" } } }, "PublishedAnalyticsBreakdown": { "type": "object", "additionalProperties": false, "required": [ "dimension", "authority", "rows", "imports", "generations", "published_at", "gross", "net", "coverage" ], "properties": { "dimension": { "$ref": "#/components/schemas/PublishedRateDimension" }, "authority": { "$ref": "#/components/schemas/PublishedAnalyticsBreakdownAuthority" }, "rows": { "type": "integer", "minimum": 1 }, "imports": { "type": "integer", "minimum": 1 }, "generations": { "type": "integer", "minimum": 1 }, "published_at": { "$ref": "#/components/schemas/IsoDateTime" }, "gross": { "$ref": "#/components/schemas/PublishedAnalyticsBreakdownSide" }, "net": { "$ref": "#/components/schemas/PublishedAnalyticsBreakdownSide" }, "coverage": { "$ref": "#/components/schemas/PublishedAnalyticsBreakdownCoverage" } } }, "PublishedAnalyticsBreakdownPage": { "type": "object", "additionalProperties": false, "required": [ "data", "meta" ], "properties": { "data": { "type": "array", "maxItems": 100, "items": { "$ref": "#/components/schemas/PublishedAnalyticsBreakdown" } }, "meta": { "type": "object", "additionalProperties": false, "required": [ "scope", "dimension", "next_cursor", "filters" ], "properties": { "scope": { "type": "string", "const": "published_generation" }, "dimension": { "$ref": "#/components/schemas/CommercialDimension" }, "next_cursor": { "type": [ "string", "null" ], "maxLength": 2048 }, "filters": { "$ref": "#/components/schemas/PublishedRateFilters" } } } } }, "PublishedRateAuthority": { "type": "object", "additionalProperties": false, "required": [ "currency", "currency_basis", "fx_set", "rate_basis" ], "properties": { "currency": { "$ref": "#/components/schemas/CurrencyCode" }, "currency_basis": { "$ref": "#/components/schemas/CurrencyBasis" }, "fx_set": { "$ref": "#/components/schemas/NullableUuid" }, "rate_basis": { "$ref": "#/components/schemas/RateBasis" } } }, "PublishedRateSide": { "type": "object", "additionalProperties": false, "required": [ "rate", "eligible_rows", "eligible_units", "eligible_revenue", "low_sample" ], "properties": { "rate": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/SignedCanonicalDecimal" } ] }, "eligible_rows": { "type": "integer", "minimum": 0 }, "eligible_units": { "$ref": "#/components/schemas/SignedCanonicalDecimal" }, "eligible_revenue": { "$ref": "#/components/schemas/SignedCanonicalDecimal" }, "low_sample": { "type": "boolean" } } }, "PublishedRateCoverage": { "type": "object", "additionalProperties": false, "required": [ "territory_percent", "subscription_plan_percent" ], "properties": { "territory_percent": { "type": [ "string", "null" ], "pattern": "^(?:0|[1-9][0-9]?|100)\\.[0-9]{10}$" }, "subscription_plan_percent": { "type": [ "string", "null" ], "pattern": "^(?:0|[1-9][0-9]?|100)\\.[0-9]{10}$" } } }, "PublishedObservedRate": { "type": "object", "additionalProperties": false, "required": [ "import", "generation", "taxonomy", "published_at", "dimension", "authority", "metric", "rows", "gross", "net", "coverage", "low_sample_units" ], "properties": { "import": { "$ref": "#/components/schemas/Uuid" }, "generation": { "$ref": "#/components/schemas/Uuid" }, "taxonomy": { "$ref": "#/components/schemas/Uuid" }, "published_at": { "$ref": "#/components/schemas/IsoDateTime" }, "dimension": { "$ref": "#/components/schemas/PublishedRateDimension" }, "authority": { "$ref": "#/components/schemas/PublishedRateAuthority" }, "metric": { "type": "string", "enum": [ "effective_cpm", "per_unit_rate" ] }, "rows": { "type": "integer", "minimum": 1 }, "gross": { "$ref": "#/components/schemas/PublishedRateSide" }, "net": { "$ref": "#/components/schemas/PublishedRateSide" }, "coverage": { "$ref": "#/components/schemas/PublishedRateCoverage" }, "low_sample_units": { "type": "integer", "minimum": 1, "maximum": 1000000000 } } }, "PublishedRateFilters": { "type": "object", "additionalProperties": false, "required": [ "currency", "currency_basis", "import", "period_start", "period_end", "dimension", "basis", "taxonomy", "state", "key" ], "properties": { "currency": { "$ref": "#/components/schemas/CurrencyCode" }, "currency_basis": { "$ref": "#/components/schemas/CurrencyBasis" }, "import": { "$ref": "#/components/schemas/NullableUuid" }, "period_start": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/ReportMonth" } ] }, "period_end": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/ReportMonth" } ] }, "dimension": { "$ref": "#/components/schemas/CommercialDimension" }, "basis": { "$ref": "#/components/schemas/RateBasis" }, "taxonomy": { "$ref": "#/components/schemas/NullableUuid" }, "state": { "oneOf": [ { "type": "null" }, { "$ref": "#/components/schemas/CommercialValueState" } ] }, "key": { "type": [ "string", "null" ], "maxLength": 160 } } }, "PublishedObservedRatePage": { "type": "object", "additionalProperties": false, "required": [ "data", "meta" ], "properties": { "data": { "type": "array", "maxItems": 100, "items": { "$ref": "#/components/schemas/PublishedObservedRate" } }, "meta": { "type": "object", "additionalProperties": false, "required": [ "scope", "dimension", "next_cursor", "filters" ], "properties": { "scope": { "type": "string", "const": "published_generation" }, "dimension": { "$ref": "#/components/schemas/CommercialDimension" }, "next_cursor": { "type": [ "string", "null" ], "maxLength": 2048 }, "filters": { "$ref": "#/components/schemas/PublishedRateFilters" } } } } } } ```