API reference
Expansion and Product Relationship API
Link expansion products, inspect parent requirements and maintain same-developer product relationships.
An expansion is a product with a relationship
Create the parent and expansion as owned products first. A relationship of expansion_requires_parent requires a parent product and describes an access prerequisite. expansion_standalone can describe independently usable content. This configuration is separate from a customer entitlement, a bundle, a file upload or a payment.
Use the owner/admin product-management context for these compatibility handlers. Both sides must belong to the same developer. Do not assume support for arbitrary delegated team roles or treat another product ID as authorization.
Read requirements before changing the relationship
GET requirements returns the product, active child relationships and required_parent_product_ids. GET relationships accepts status=active or inactive. GET expansions lists linked children for a parent. Refresh these views after a change; product configuration does not prove that a customer owns the required parent.
Creation rejects duplicate active and circular relationships. DELETE deactivates a relationship; it does not delete the products, refund the expansion or erase historical orders. Use the relationship action rather than assuming that clearing a parent field removes every active prerequisite.
SoundSync
Illustrative parent requirement
curl --fail-with-body -sS -X POST "$SOUNDSYNC_API_BASE/api/developer/product-relationships" \
-H "Authorization: Bearer $DEVELOPER_TOKEN" -H "Content-Type: application/json" \
--data '{"parentProductId":123,"childProductId":124,"relationshipType":"expansion_requires_parent"}'
Visibility and access are different
The supported expansion configuration includes public, unlisted or hidden visibility, sort order, parent requirement, parent-access setting and extension metadata. These fields do not bypass customer licensing or download authorization. Test the actual parent-owned and parent-missing customer paths before publishing.
SoundSync
Related product decisions
SoundSync
Requests and responses
/api/developer/products/{productId}/expansions
List linked expansion products
- Auth
- Account Bearer JWT
- Scope
- Owner/admin product-management surface. Both parent and child must belong to the same developer. Do not assume these compatibility handlers support every delegated team role.
- Returns
- HTTP 200: parent, expansions.
Request, response and error reference
No request body fields are read by this operation.
HTTP 200 response (application/json)
{
"type": "object",
"properties": {
"parent": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"minimum": 1
},
"productId": {
"type": "integer",
"minimum": 1
},
"name": {
"type": "string"
},
"productType": {
"type": "string"
},
"isExpansion": {
"type": "boolean"
},
"parentProductId": {
"type": [
"integer",
"null"
]
},
"requiredParentProductIds": {
"type": "array",
"items": {
"type": "integer",
"minimum": 1
}
},
"requiresParentEntitlement": {
"type": "boolean"
},
"grantsParentAccess": {
"type": "boolean"
},
"visibility": {
"type": "string",
"enum": [
"public",
"unlisted",
"hidden"
]
},
"expansionSortOrder": {
"type": "integer"
},
"expansionAccessState": {
"type": "string"
},
"expansionMetadata": {
"type": "object",
"additionalProperties": true,
"description": "Operation-specific extension data; do not put credentials or unnecessary personal information here."
},
"ownerUserId": {
"type": "integer",
"minimum": 1
},
"marketplaceVisible": {
"type": "boolean"
},
"isDraft": {
"type": "boolean"
}
},
"additionalProperties": true
},
"expansions": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"minimum": 1
},
"productId": {
"type": "integer",
"minimum": 1
},
"name": {
"type": "string"
},
"productType": {
"type": "string"
},
"isExpansion": {
"type": "boolean"
},
"parentProductId": {
"type": [
"integer",
"null"
]
},
"requiredParentProductIds": {
"type": "array",
"items": {
"type": "integer",
"minimum": 1
}
},
"requiresParentEntitlement": {
"type": "boolean"
},
"grantsParentAccess": {
"type": "boolean"
},
"visibility": {
"type": "string",
"enum": [
"public",
"unlisted",
"hidden"
]
},
"expansionSortOrder": {
"type": "integer"
},
"expansionAccessState": {
"type": "string"
},
"expansionMetadata": {
"type": "object",
"additionalProperties": true,
"description": "Operation-specific extension data; do not put credentials or unnecessary personal information here."
},
"ownerUserId": {
"type": "integer",
"minimum": 1
},
"marketplaceVisible": {
"type": "boolean"
},
"isDraft": {
"type": "boolean"
}
},
"additionalProperties": true
}
}
},
"additionalProperties": true
}
Documented failures: 400, 401, 403, 404, 409, 500.
/api/developer/products/{productId}/relationships
Read active or inactive product relationships
- Auth
- Account Bearer JWT
- Scope
- Owner/admin product-management surface. Both parent and child must belong to the same developer. Do not assume these compatibility handlers support every delegated team role.
- Request fields
- query status: string
- Returns
- HTTP 200: relationships.
Request, response and error reference
Query and header parameters
[
{
"name": "status",
"in": "query",
"schema": {
"type": "string",
"enum": [
"active",
"inactive"
]
},
"required": false,
"description": ""
}
]
No request body fields are read by this operation.
HTTP 200 response (application/json)
{
"type": "object",
"properties": {
"relationships": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"minimum": 1
},
"developerId": {
"type": "integer",
"minimum": 1
},
"parentProductId": {
"type": [
"integer",
"null"
]
},
"childProductId": {
"type": "integer",
"minimum": 1
},
"relationshipType": {
"type": "string",
"enum": [
"expansion_requires_parent",
"expansion_standalone"
]
},
"status": {
"type": "string"
},
"metadata": {
"type": "object",
"additionalProperties": true,
"description": "Operation-specific extension data; do not put credentials or unnecessary personal information here."
},
"createdAt": {
"type": [
"string",
"null"
],
"format": "date-time"
},
"updatedAt": {
"type": [
"string",
"null"
],
"format": "date-time"
}
},
"additionalProperties": true
}
}
},
"additionalProperties": true
}
Documented failures: 400, 401, 403, 404, 409, 500.
/api/developer/products/{productId}/requirements
Read parent-product access requirements
- Auth
- Account Bearer JWT
- Scope
- Owner/admin product-management surface. Both parent and child must belong to the same developer. Do not assume these compatibility handlers support every delegated team role.
- Returns
- HTTP 200: product, relationships, required_parent_product_ids.
Request, response and error reference
No request body fields are read by this operation.
HTTP 200 response (application/json)
{
"type": "object",
"properties": {
"product": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"minimum": 1
},
"productId": {
"type": "integer",
"minimum": 1
},
"name": {
"type": "string"
},
"productType": {
"type": "string"
},
"isExpansion": {
"type": "boolean"
},
"parentProductId": {
"type": [
"integer",
"null"
]
},
"requiredParentProductIds": {
"type": "array",
"items": {
"type": "integer",
"minimum": 1
}
},
"requiresParentEntitlement": {
"type": "boolean"
},
"grantsParentAccess": {
"type": "boolean"
},
"visibility": {
"type": "string",
"enum": [
"public",
"unlisted",
"hidden"
]
},
"expansionSortOrder": {
"type": "integer"
},
"expansionAccessState": {
"type": "string"
},
"expansionMetadata": {
"type": "object",
"additionalProperties": true,
"description": "Operation-specific extension data; do not put credentials or unnecessary personal information here."
},
"ownerUserId": {
"type": "integer",
"minimum": 1
},
"marketplaceVisible": {
"type": "boolean"
},
"isDraft": {
"type": "boolean"
}
},
"additionalProperties": true
},
"relationships": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"minimum": 1
},
"developerId": {
"type": "integer",
"minimum": 1
},
"parentProductId": {
"type": [
"integer",
"null"
]
},
"childProductId": {
"type": "integer",
"minimum": 1
},
"relationshipType": {
"type": "string",
"enum": [
"expansion_requires_parent",
"expansion_standalone"
]
},
"status": {
"type": "string"
},
"metadata": {
"type": "object",
"additionalProperties": true,
"description": "Operation-specific extension data; do not put credentials or unnecessary personal information here."
},
"createdAt": {
"type": [
"string",
"null"
],
"format": "date-time"
},
"updatedAt": {
"type": [
"string",
"null"
],
"format": "date-time"
}
},
"additionalProperties": true
}
},
"required_parent_product_ids": {
"type": "array",
"items": {
"type": "integer",
"minimum": 1
}
}
},
"additionalProperties": true
}
Documented failures: 400, 401, 403, 404, 409, 500.
/api/developer/product-relationships
Create a same-developer parent/expansion relationship
- Auth
- Account Bearer JWT
- Scope
- Owner/admin product-management surface. Both parent and child must belong to the same developer. Do not assume these compatibility handlers support every delegated team role.
- Request fields
- parentProductId: integer,null
- parent_product_id: integer,null
- childProductId: integer
- child_product_id: integer
- relationshipType: expansion_requires_parent | expansion_standalone
- relationship_type: expansion_requires_parent | expansion_standalone
- metadata: object. Operation-specific extension data; do not put credentials or unnecessary personal information here.
- Returns
- HTTP 201: relationship, created.
- Notes
- expansion_requires_parent is the default and requires parentProductId. Standalone relationships can omit the parent. Snake_case aliases are accepted. Duplicate active relationships return 409; self/circular relationships are rejected.
Request, response and error reference
Request (application/json)
{
"type": "object",
"properties": {
"parentProductId": {
"type": [
"integer",
"null"
]
},
"parent_product_id": {
"type": [
"integer",
"null"
]
},
"childProductId": {
"type": "integer",
"minimum": 1
},
"child_product_id": {
"type": "integer",
"minimum": 1
},
"relationshipType": {
"type": "string",
"enum": [
"expansion_requires_parent",
"expansion_standalone"
]
},
"relationship_type": {
"type": "string",
"enum": [
"expansion_requires_parent",
"expansion_standalone"
]
},
"metadata": {
"type": "object",
"additionalProperties": true,
"description": "Operation-specific extension data; do not put credentials or unnecessary personal information here."
}
},
"additionalProperties": true,
"anyOf": [
{
"required": [
"childProductId"
]
},
{
"required": [
"child_product_id"
]
}
]
}
HTTP 201 response (application/json)
{
"type": "object",
"properties": {
"relationship": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"minimum": 1
},
"developerId": {
"type": "integer",
"minimum": 1
},
"parentProductId": {
"type": [
"integer",
"null"
]
},
"childProductId": {
"type": "integer",
"minimum": 1
},
"relationshipType": {
"type": "string",
"enum": [
"expansion_requires_parent",
"expansion_standalone"
]
},
"status": {
"type": "string"
},
"metadata": {
"type": "object",
"additionalProperties": true,
"description": "Operation-specific extension data; do not put credentials or unnecessary personal information here."
},
"createdAt": {
"type": [
"string",
"null"
],
"format": "date-time"
},
"updatedAt": {
"type": [
"string",
"null"
],
"format": "date-time"
}
},
"additionalProperties": true
},
"created": {
"type": "boolean"
}
},
"additionalProperties": true
}
Documented failures: 400, 401, 403, 404, 409, 500.
/api/developer/product-relationships/{relationshipId}
Deactivate a relationship without deleting products
- Auth
- Account Bearer JWT
- Scope
- Owner/admin product-management surface. Both parent and child must belong to the same developer. Do not assume these compatibility handlers support every delegated team role.
- Returns
- HTTP 200: relationship.
- Notes
- Removes the active requirement relationship, not the product, payment or previously issued order.
Request, response and error reference
No request body fields are read by this operation.
HTTP 200 response (application/json)
{
"type": "object",
"properties": {
"relationship": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"minimum": 1
},
"developerId": {
"type": "integer",
"minimum": 1
},
"parentProductId": {
"type": [
"integer",
"null"
]
},
"childProductId": {
"type": "integer",
"minimum": 1
},
"relationshipType": {
"type": "string",
"enum": [
"expansion_requires_parent",
"expansion_standalone"
]
},
"status": {
"type": "string"
},
"metadata": {
"type": "object",
"additionalProperties": true,
"description": "Operation-specific extension data; do not put credentials or unnecessary personal information here."
},
"createdAt": {
"type": [
"string",
"null"
],
"format": "date-time"
},
"updatedAt": {
"type": [
"string",
"null"
],
"format": "date-time"
}
},
"additionalProperties": true
}
},
"additionalProperties": true
}
Documented failures: 400, 401, 403, 404, 409, 500.
/api/developer/products/{productId}/expansions
Link an existing expansion to this parent
- Auth
- Account Bearer JWT
- Scope
- Owner/admin product-management surface. Both parent and child must belong to the same developer. Do not assume these compatibility handlers support every delegated team role.
- Request fields
- parentProductId: integer,null
- productType: string
- expansionVisibility: public | unlisted | hidden
- requiresParentEntitlement: boolean
- grantsParentAccess: boolean
- expansionSortOrder: integer
- expansionMetadata: object. Operation-specific extension data; do not put credentials or unnecessary personal information here.
- expansionProductId: integer
- expansion_product_id: integer
- Returns
- HTTP 201: expansion.
Request, response and error reference
Request (application/json)
{
"type": "object",
"properties": {
"parentProductId": {
"type": [
"integer",
"null"
]
},
"productType": {
"type": "string"
},
"expansionVisibility": {
"type": "string",
"enum": [
"public",
"unlisted",
"hidden"
]
},
"requiresParentEntitlement": {
"type": "boolean"
},
"grantsParentAccess": {
"type": "boolean"
},
"expansionSortOrder": {
"type": "integer"
},
"expansionMetadata": {
"type": "object",
"additionalProperties": true,
"description": "Operation-specific extension data; do not put credentials or unnecessary personal information here."
},
"expansionProductId": {
"type": "integer",
"minimum": 1
},
"expansion_product_id": {
"type": "integer",
"minimum": 1
}
},
"additionalProperties": true,
"anyOf": [
{
"required": [
"expansionProductId"
]
},
{
"required": [
"expansion_product_id"
]
}
]
}
HTTP 201 response (application/json)
{
"type": "object",
"properties": {
"expansion": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"minimum": 1
},
"productId": {
"type": "integer",
"minimum": 1
},
"name": {
"type": "string"
},
"productType": {
"type": "string"
},
"isExpansion": {
"type": "boolean"
},
"parentProductId": {
"type": [
"integer",
"null"
]
},
"requiredParentProductIds": {
"type": "array",
"items": {
"type": "integer",
"minimum": 1
}
},
"requiresParentEntitlement": {
"type": "boolean"
},
"grantsParentAccess": {
"type": "boolean"
},
"visibility": {
"type": "string",
"enum": [
"public",
"unlisted",
"hidden"
]
},
"expansionSortOrder": {
"type": "integer"
},
"expansionAccessState": {
"type": "string"
},
"expansionMetadata": {
"type": "object",
"additionalProperties": true,
"description": "Operation-specific extension data; do not put credentials or unnecessary personal information here."
},
"ownerUserId": {
"type": "integer",
"minimum": 1
},
"marketplaceVisible": {
"type": "boolean"
},
"isDraft": {
"type": "boolean"
}
},
"additionalProperties": true
}
},
"additionalProperties": true
}
Documented failures: 400, 401, 403, 404, 409, 500.
/api/developer/products/{productId}/expansion
Update expansion configuration
- Auth
- Account Bearer JWT
- Scope
- Owner/admin product-management surface. Both parent and child must belong to the same developer. Do not assume these compatibility handlers support every delegated team role.
- Request fields
- parentProductId: integer,null
- productType: string
- expansionVisibility: public | unlisted | hidden
- requiresParentEntitlement: boolean
- grantsParentAccess: boolean
- expansionSortOrder: integer
- expansionMetadata: object. Operation-specific extension data; do not put credentials or unnecessary personal information here.
- Returns
- HTTP 200: expansion.
- Notes
- Supported snake_case aliases are accepted. Setting a parent can create a relationship. To remove an active relationship, use the relationship deletion endpoint and reload requirements; a parent field alone is not the complete relationship history.
Request, response and error reference
Request (application/json)
{
"type": "object",
"properties": {
"parentProductId": {
"type": [
"integer",
"null"
]
},
"productType": {
"type": "string"
},
"expansionVisibility": {
"type": "string",
"enum": [
"public",
"unlisted",
"hidden"
]
},
"requiresParentEntitlement": {
"type": "boolean"
},
"grantsParentAccess": {
"type": "boolean"
},
"expansionSortOrder": {
"type": "integer"
},
"expansionMetadata": {
"type": "object",
"additionalProperties": true,
"description": "Operation-specific extension data; do not put credentials or unnecessary personal information here."
}
},
"additionalProperties": true
}
HTTP 200 response (application/json)
{
"type": "object",
"properties": {
"expansion": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"minimum": 1
},
"productId": {
"type": "integer",
"minimum": 1
},
"name": {
"type": "string"
},
"productType": {
"type": "string"
},
"isExpansion": {
"type": "boolean"
},
"parentProductId": {
"type": [
"integer",
"null"
]
},
"requiredParentProductIds": {
"type": "array",
"items": {
"type": "integer",
"minimum": 1
}
},
"requiresParentEntitlement": {
"type": "boolean"
},
"grantsParentAccess": {
"type": "boolean"
},
"visibility": {
"type": "string",
"enum": [
"public",
"unlisted",
"hidden"
]
},
"expansionSortOrder": {
"type": "integer"
},
"expansionAccessState": {
"type": "string"
},
"expansionMetadata": {
"type": "object",
"additionalProperties": true,
"description": "Operation-specific extension data; do not put credentials or unnecessary personal information here."
},
"ownerUserId": {
"type": "integer",
"minimum": 1
},
"marketplaceVisible": {
"type": "boolean"
},
"isDraft": {
"type": "boolean"
}
},
"additionalProperties": true
}
},
"additionalProperties": true
}
Documented failures: 400, 401, 403, 404, 409, 500.
/api/developer/products/{productId}/expansion
Update expansion configuration
- Auth
- Account Bearer JWT
- Scope
- Owner/admin product-management surface. Both parent and child must belong to the same developer. Do not assume these compatibility handlers support every delegated team role.
- Request fields
- parentProductId: integer,null
- productType: string
- expansionVisibility: public | unlisted | hidden
- requiresParentEntitlement: boolean
- grantsParentAccess: boolean
- expansionSortOrder: integer
- expansionMetadata: object. Operation-specific extension data; do not put credentials or unnecessary personal information here.
- Returns
- HTTP 200: expansion.
- Notes
- Supported snake_case aliases are accepted. Setting a parent can create a relationship. To remove an active relationship, use the relationship deletion endpoint and reload requirements; a parent field alone is not the complete relationship history.
Request, response and error reference
Request (application/json)
{
"type": "object",
"properties": {
"parentProductId": {
"type": [
"integer",
"null"
]
},
"productType": {
"type": "string"
},
"expansionVisibility": {
"type": "string",
"enum": [
"public",
"unlisted",
"hidden"
]
},
"requiresParentEntitlement": {
"type": "boolean"
},
"grantsParentAccess": {
"type": "boolean"
},
"expansionSortOrder": {
"type": "integer"
},
"expansionMetadata": {
"type": "object",
"additionalProperties": true,
"description": "Operation-specific extension data; do not put credentials or unnecessary personal information here."
}
},
"additionalProperties": true
}
HTTP 200 response (application/json)
{
"type": "object",
"properties": {
"expansion": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"minimum": 1
},
"productId": {
"type": "integer",
"minimum": 1
},
"name": {
"type": "string"
},
"productType": {
"type": "string"
},
"isExpansion": {
"type": "boolean"
},
"parentProductId": {
"type": [
"integer",
"null"
]
},
"requiredParentProductIds": {
"type": "array",
"items": {
"type": "integer",
"minimum": 1
}
},
"requiresParentEntitlement": {
"type": "boolean"
},
"grantsParentAccess": {
"type": "boolean"
},
"visibility": {
"type": "string",
"enum": [
"public",
"unlisted",
"hidden"
]
},
"expansionSortOrder": {
"type": "integer"
},
"expansionAccessState": {
"type": "string"
},
"expansionMetadata": {
"type": "object",
"additionalProperties": true,
"description": "Operation-specific extension data; do not put credentials or unnecessary personal information here."
},
"ownerUserId": {
"type": "integer",
"minimum": 1
},
"marketplaceVisible": {
"type": "boolean"
},
"isDraft": {
"type": "boolean"
}
},
"additionalProperties": true
}
},
"additionalProperties": true
}
Documented failures: 400, 401, 403, 404, 409, 500.
