Skip to content
SoundSyncAudio software platform

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

Link two owned products
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

Product model

Products, bundles and configured capabilities.

Entitlements

Customer access is separate from relationship configuration.

SoundSync

Requests and responses

GET /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.

GET /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.

GET /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.

POST /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.

DELETE /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.

POST /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.

PUT /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.

PATCH /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.