Distribution
Manage buyer portals, buyers and deals, record title licenses, and check avails and platform submissions.
Distribution is the sell side of your catalog. A portal is a branded catalog you expose to buyers. A buyer is a company you sell to. A deal moves through stages from a buyer's request to delivery. A license is a record on a title of who holds what, where and for how long.
Rules the server enforces
- Rights are never inferred. A license is a record. It is not an availability authority and never changes a title's rights status; rights windows on the title do that. See Rights.
- Exclusive licenses can't silently overlap. A conflicting exclusive license is refused with
409 CONFLICTunless you override it with a reason, which is audited. - Viewers can't change licenses. A
viewerkey gets403 FORBIDDENwhen saving one. - A portal only shows what you've curated. Titles with expired rights can be hidden from it automatically.
Portals
curl https://dev.app.ingenee.ai/api/v1/portals \
-H "Authorization: Bearer $INGENEE_API_KEY"GET /v1/portals returns { portals: [...] }; GET /v1/portals/{id} returns { portal }:
{
"portal": {
"id": "2c3d4e5f-6a7b-4c8d-9e0f-1a2b3c4d5e6f",
"slug": "ingenee-drama-avails",
"name": "Ingenee drama avails",
"status": "draft",
"accessMode": "password",
"hasPassword": true,
"contentKind": "titles",
"catalogIds": ["0e578f59-bf28-455f-bc82-f0639a7575fb"],
"assetIds": [],
"hiddenAssetIds": [],
"channelIds": [],
"hideExpiredRights": true,
"buyerId": null,
"accentColor": "#2f6fed",
"about": "Scripted drama available for AVOD and FAST.",
"contactEmail": "licensing@example.com"
}
}PATCH /v1/portals/{id} changes any of: name, slug, logoUrl, coverUrl, accentColor, logoBgColor, about,
contactEmail, contactPhone, websiteUrl, catalogIds, assetIds (explicit titles), hiddenAssetIds, channelIds,
hiddenChannelIds, hideExpiredRights, buyerId, status (draft or published), accessMode, password and
restrictedDomains.
curl -X PATCH https://dev.app.ingenee.ai/api/v1/portals/2c3d4e5f-6a7b-4c8d-9e0f-1a2b3c4d5e6f \
-H "Authorization: Bearer $INGENEE_API_KEY" -H "content-type: application/json" \
-d '{ "catalogIds": ["0e578f59-bf28-455f-bc82-f0639a7575fb"], "accessMode": "company_restricted", "restrictedDomains": ["buyer.example.com"], "status": "published" }'- Slug. An explicit
slugis used exactly or refused (409 CONFLICTif taken,422if it isn't lower-case letters, numbers and hyphens). It is never silently suffixed. - Access.
accessModeispublic,private,password,invite,company_restricted,buyer_specific,team_membersorsales_reps.company_restrictedneeds at least one bare domain inrestrictedDomains, andbuyer_specificneedsaccessBoundBuyerId, or the call returns422rather than leave the portal open. The password is stored hashed and never returned;hasPasswordsays whether one is set. - Images.
logoUrlandcoverUrltake anhttp(s)URL or an image data URL. - Curation.
catalogIds,assetIdsandhiddenAssetIdsdecide what buyers see. An emptycatalogIdsandassetIdsmeans everything not hidden.
Licensing requests from buyers arrive on GET /v1/portals/{id}/requests: { requests, newCount }, each with the buyer's name,
company, email, message, requested territories, license types and window, status and the titleName. A request with
convertedDealId has already become a deal.
Buyers
curl -X POST https://dev.app.ingenee.ai/api/v1/distribution/buyers \
-H "Authorization: Bearer $INGENEE_API_KEY" -H "content-type: application/json" \
-d '{ "name": "Northlight Media", "type": "fast_platform", "website": "https://northlight.example.com",
"territories": ["US", "CA"], "genreFocus": ["Drama", "Crime"], "businessModels": ["FAST"] }'201 with { "buyer": { … } }. Only name is required. type is svod, avod, tvod, fast_platform, fast_channel,
broadcaster, cable or other (default). territories are upper-cased. A buyer you add is private to your organization.
GET /v1/distribution/buyers returns { buyers, total, facets }. Filters: q, type, territory, genre, businessModel, status
(active, inactive, unknown), limit (1 to 200, default 50) and offset. GET /v1/distribution/buyers/{id} returns
the buyer with its evidence signals, contacts and your organization's own notes. The list can include buyers Ingenee maintains
for all organizations; yours have isGlobal: false.
Deals
curl "https://dev.app.ingenee.ai/api/v1/distribution/deals?stage=approved" \
-H "Authorization: Bearer $INGENEE_API_KEY"GET /v1/distribution/deals returns { deals, counts, convertibleRequests, recorded }. recorded.value is null, not 0, when no
won deal carries a price. GET /v1/distribution/deals/{id} returns { deal, titles, events, requestEvents, rights, emails, screeners, marketing }.
A deal's stage is new, approved, titles_sent, won, delivered or declined. Move it with a stage and an optional note:
curl -X POST https://dev.app.ingenee.ai/api/v1/distribution/deals/7d8e9f0a-1b2c-4d3e-8f4a-5b6c7d8e9f01/stage \
-H "Authorization: Bearer $INGENEE_API_KEY" -H "content-type: application/json" \
-d '{ "stage": "won", "note": "Signed 2026-10-28" }'{ "stage": "won", "from": "titles_sent" }The move is appended to the deal's history; going back a stage is recorded too, never overwritten. Moving to the stage a deal is
already in returns { "stage": "won", "unchanged": true }. Reaching won records the time.
Licenses on a title
curl -X POST https://dev.app.ingenee.ai/api/v1/titles/7c1a3f0e-5d2b-4f6a-9a41-2f0e9d3b8c11/licenses \
-H "Authorization: Bearer $INGENEE_API_KEY" -H "content-type: application/json" \
-d '{
"licensee": "Northlight Media",
"distributionType": "fast",
"startDate": "2026-12-01",
"endDate": "2027-11-30",
"worldwide": false,
"territories": ["US", "CA"],
"exclusive": true,
"dealType": "flat_fee",
"currency": "USD",
"licenseFee": 25000
}'{ "license": { "id": "…", "licensee": "Northlight Media", "distributionType": "fast", "status": "upcoming", "exclusive": true, "territories": ["US", "CA"] }, "warnings": [] }| Field | Notes |
|---|---|
licensee | Required, up to 200 characters |
distributionType | Required: avod, svod, tvod, fast, linear, broadcast, theatrical or other |
startDate, endDate | YYYY-MM-DD, or null for open. The end can't be before the start |
worldwide, territories | Either worldwide: true with no list, or false with at least one two-letter code |
exclusive | Exclusive licenses are checked for overlap |
dealType | owned, flat_fee, revenue_share or mg_revenue_share, with licenseFee, mgAmount, revenueShareLicensor, revenueShareLicensee (0 to 100), settlementFrequency (monthly, quarterly, yearly), currency |
dealId | Link to one of the deals that applies to this title or its catalog |
notes | Up to 4,000 characters |
status is computed on the server from the dates: current, upcoming or expired.
If the new exclusive license overlaps another on this title in time and territory, the save is refused:
{ "error": { "code": "CONFLICT", "message": "Blocked: overlaps … Override with a reason to save anyway.",
"details": { "code": "LICENSE_EXCLUSIVE_OVERLAP", "conflicts": [ ] } } }To save anyway, resend with "override": true and an "overrideReason". An override without a reason returns
422 (details.code of LICENSE_OVERRIDE_REASON_REQUIRED). The reason and who overrode are stored on the license.
GET /v1/titles/{id}/licenses returns { licenses, dealLabels, warnings, today }. PATCH /v1/titles/{id}/licenses/{licenseId} takes
the same fields as create and returns { license, warnings }. DELETE /v1/titles/{id}/licenses/{licenseId} returns { "deleted": true }.
Check an avails sheet
POST /v1/rights/avails/preview reads avails rows and says how they would match your Library. It writes nothing.
curl -X POST https://dev.app.ingenee.ai/api/v1/rights/avails/preview \
-H "Authorization: Bearer $INGENEE_API_KEY" -H "content-type: application/json" \
-d '{ "rows": [ { "title": "The Long Night", "year": 2019,
"rights": [ { "scope": "AVOD", "territory": "US", "licenseStart": "2026-01-01", "licenseEnd": "2027-12-31" } ] } ] }'{
"matched": [ { "title": "The Long Night", "assetId": "1b478b6a-…", "assetTitle": "The Long Night", "match": 1,
"windows": [ { "scope": "AVOD", "territory": "US", "start": "2026-01-01", "end": "2027-12-31" } ] } ],
"needsReview": [ ],
"fieldIssues": [ ],
"counts": { "matched": 1, "needsReview": 0, "fieldIssues": 0 }
}matched rows found a title with the same name (within a year). needsReview rows have only a fuzzy candidate in best, which a person
must confirm. fieldIssues have no usable rights window. Up to 5,000 rows per call. Scope names are mapped to Ingenee's scopes
(Theatrical, SVOD, TV, AVOD, FAST, TVOD). To record rights, add windows to titles with
POST /v1/titles/{id}/rights, which is always an explicit decision.
Platform submissions
GET /v1/distribution/submissions returns the directory of distribution platforms, the state of each submission you've tracked
(per platform and channel), your channels that can be offered, your own requests for platforms not in the directory, and
counts (platforms, notStarted, considering, preparing, submitted, accepted, declined, openRequests). It is read-only.
Not yet available
- Creating or deleting a portal, managing portal invitations, and replying to licensing requests.
- Changing a request's status, or converting a request into a deal.
- Updating submission states and applying an avails sheet in bulk.
- Webhook events for deals or requests. See the available events.
Endpoints
| Operation | Method + path | Scope |
|---|---|---|
| List buyer portals | GET /v1/portals | distribution:read |
| Get a portal | GET /v1/portals/{id} | distribution:read |
| Update a portal | PATCH /v1/portals/{id} | distribution:write |
| List licensing requests | GET /v1/portals/{id}/requests | distribution:read |
| List buyers | GET /v1/distribution/buyers | distribution:read |
| Add a buyer | POST /v1/distribution/buyers | distribution:write |
| Get a buyer | GET /v1/distribution/buyers/{id} | distribution:read |
| List deals | GET /v1/distribution/deals | distribution:read |
| Get a deal | GET /v1/distribution/deals/{id} | distribution:read |
| Move a deal to a stage | POST /v1/distribution/deals/{id}/stage | distribution:write |
| List a title's licenses | GET /v1/titles/{id}/licenses | distribution:read |
| Record a license | POST /v1/titles/{id}/licenses | distribution:write |
| Update a license | PATCH /v1/titles/{id}/licenses/{licenseId} | distribution:write |
| Delete a license | DELETE /v1/titles/{id}/licenses/{licenseId} | distribution:write |
| Partner submissions and status | GET /v1/distribution/submissions | distribution:read |
| Preview an avails sheet | POST /v1/rights/avails/preview | distribution:read |