API reference
Protected Content API
Private archive publication, compatible customer catalogs, signed native content permissions and private delivery.
Deliver encrypted expansion content
Protected content packages your expansion archive into a signed, encrypted .sspc release in managed private storage. Customers receive compatible releases through their permitted library or integrated JUCE client. Keep your own expansion browser, content format and audio engine.
Private download authorization and playback authorization are different. Verify the package and the signed product/content permission in the maintained SDK. Ordinary downloaded files cannot be recalled or made securely temporary by a later account change. Do not expose the raw protected source as a normal customer download.
SoundSync
Authoring, customer delivery and native catalog
/api/products/{id}/protected-content
List the product protected content and immutable releases
- Auth
- Account Bearer session token
- Scope
- Owned and assigned product. products.view for release listing, products.edit for private upload steps, products.publish for packaging/publication.
- Returns
- HTTP 200: releases.
- Notes
- An identity without a published release returns null releaseId, revision, status and publishedAt. Creator records expose eligibility metadata, not customer-owned/available playback fields. Current product management verifies workspace permissions and any product ownership/assignment before database writes or AI work. Creating a product or using untargeted new-product AI requires products.create and all-products scope. Existing-product edits/AI use products.edit, file operations use product_files permissions, scheduled-deal writes use marketing.manage, and purchase-option deal publication retains products.publish. Statistics require analytics.view. Publication/archival keep their dedicated permissions. The effective workspace developer owns new products; the teammate remains the audit actor.
Request, response and error reference
No request body fields are read by this operation.
HTTP 200 response (application/json)
{
"type": "object",
"properties": {
"releases": {
"type": "array",
"items": {
"type": "object",
"properties": {
"contentId": {
"type": "string",
"format": "uuid"
},
"parentProductId": {
"anyOf": [
{
"type": "integer",
"minimum": 1
},
{
"type": "null"
}
]
},
"eligibleForFutureInclusion": {
"type": "boolean"
},
"releaseId": {
"anyOf": [
{
"type": "string",
"format": "uuid"
},
{
"type": "null"
}
]
},
"revision": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"status": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"publishedAt": {
"anyOf": [
{
"type": "string",
"format": "date-time"
},
{
"type": "null"
}
]
}
},
"additionalProperties": true
}
}
},
"additionalProperties": true
}
Documented failures: 400, 401, 403, 404, 409, 500, 503.
/api/products/{id}/protected-content/uploads
Start a private protected-archive upload
- Auth
- Account Bearer session token
- Scope
- Owned and assigned product. products.view for release listing, products.edit for private upload steps, products.publish for packaging/publication.
- Request fields
- contentId: string
- revision: string (required)
- compatibleMajorVersions: array (required)
- minimumHostVersion: string
- filename: string (required)
- sizeBytes: integer (required)
- mimeType: string
- multipart: boolean
- fileFingerprint: string
- Returns
- HTTP 200: job, upload.
- Notes
- One archive up to 512 MiB. contentId may be omitted to reuse/register the product archive identity. job.id is an opaque decimal string, not the content/release UUID. minimumHostVersion defaults to 0.0.0 if omitted; explicitly set the real requirement for your bank. This is not an ordinary plaintext download attachment. Keep upload URLs private. Use the returned upload plan; small files may receive a direct PUT while multipart uploads request individual parts. A fingerprint describes the actual complete file, not its name. Current product management verifies workspace permissions and any product ownership/assignment before database writes or AI work. Creating a product or using untargeted new-product AI requires products.create and all-products scope. Existing-product edits/AI use products.edit, file operations use product_files permissions, scheduled-deal writes use marketing.manage, and purchase-option deal publication retains products.publish. Statistics require analytics.view. Publication/archival keep their dedicated permissions. The effective workspace developer owns new products; the teammate remains the audit actor.
Request, response and error reference
Request (application/json)
{
"type": "object",
"properties": {
"contentId": {
"type": "string",
"format": "uuid"
},
"revision": {
"type": "string",
"minLength": 1,
"maxLength": 128
},
"compatibleMajorVersions": {
"type": "array",
"minItems": 1,
"maxItems": 16,
"items": {
"anyOf": [
{
"type": "string",
"pattern": "^(0|[1-9][0-9]{0,8})$"
},
{
"type": "integer",
"minimum": 0,
"maximum": 999999999
}
]
}
},
"minimumHostVersion": {
"type": "string",
"pattern": "^[0-9]{1,9}\\.[0-9]{1,9}\\.[0-9]{1,9}$",
"default": "0.0.0"
},
"filename": {
"type": "string",
"minLength": 1
},
"sizeBytes": {
"type": "integer",
"minimum": 1,
"maximum": 536870912
},
"mimeType": {
"type": "string"
},
"multipart": {
"type": "boolean"
},
"fileFingerprint": {
"type": "string",
"pattern": "^v1:[a-f0-9]{64}$"
}
},
"additionalProperties": true,
"required": [
"revision",
"compatibleMajorVersions",
"filename",
"sizeBytes"
]
}
HTTP 200 response (application/json)
{
"type": "object",
"properties": {
"job": {
"type": "object",
"properties": {
"id": {
"type": "string",
"pattern": "^[1-9][0-9]*$",
"description": "Opaque decimal upload-job identifier, not a content/release UUID."
},
"productId": {
"anyOf": [
{
"type": "integer",
"minimum": 1
},
{
"type": "null"
}
]
},
"sourceType": {
"type": "string"
},
"protectedContent": {
"type": "boolean"
},
"originalFilename": {
"type": "string"
},
"filename": {
"type": "string"
},
"storageKey": {
"type": "string"
},
"fileSizeBytes": {
"anyOf": [
{
"type": "integer",
"minimum": 0
},
{
"type": "null"
}
]
},
"expectedSizeBytes": {
"anyOf": [
{
"type": "integer",
"minimum": 0
},
{
"type": "null"
}
]
},
"mimeType": {
"type": "string"
},
"checksum": {
"type": "string"
},
"status": {
"type": "string"
},
"progress": {
"type": "integer",
"minimum": 0
},
"errorCode": {
"type": "string"
},
"errorMessage": {
"type": "string"
},
"attachedProductFileId": {
"type": "string"
},
"createdAt": {
"type": "string",
"format": "date-time"
},
"updatedAt": {
"type": "string",
"format": "date-time"
},
"completedAt": {
"anyOf": [
{
"type": "string",
"format": "date-time"
},
{
"type": "null"
}
]
},
"resumable": {
"type": "boolean"
},
"expiresAt": {
"anyOf": [
{
"type": "string",
"format": "date-time"
},
{
"type": "null"
}
]
}
},
"additionalProperties": true
},
"upload": {
"type": "object",
"properties": {
"url": {
"type": "string"
},
"method": {
"type": "string"
},
"headers": {
"type": "object",
"properties": {},
"additionalProperties": true
},
"multipart": {
"type": "boolean"
},
"partSize": {
"type": "integer",
"minimum": 0
},
"partCount": {
"type": "integer",
"minimum": 0
},
"completedPartNumbers": {
"type": "array",
"items": {
"type": "integer",
"minimum": 1
}
},
"expiresAt": {
"type": "string",
"format": "date-time"
},
"resumed": {
"type": "boolean"
},
"completed": {
"type": "boolean"
}
},
"additionalProperties": true
}
},
"additionalProperties": true
}
Documented failures: 400, 401, 403, 404, 409, 500, 503.
/api/products/{id}/protected-content/uploads/{jobId}/part
Prepare one private multipart PUT
- Auth
- Account Bearer session token
- Scope
- Owned and assigned product. products.view for release listing, products.edit for private upload steps, products.publish for packaging/publication.
- Request fields
- partNumber: integer (required)
- Returns
- HTTP 200: upload.
- Notes
- Use only for the returned multipart plan. Upload the indicated bytes to its signed URL; this API call does not carry the archive bytes. Current product management verifies workspace permissions and any product ownership/assignment before database writes or AI work. Creating a product or using untargeted new-product AI requires products.create and all-products scope. Existing-product edits/AI use products.edit, file operations use product_files permissions, scheduled-deal writes use marketing.manage, and purchase-option deal publication retains products.publish. Statistics require analytics.view. Publication/archival keep their dedicated permissions. The effective workspace developer owns new products; the teammate remains the audit actor.
Request, response and error reference
Request (application/json)
{
"type": "object",
"properties": {
"partNumber": {
"type": "integer",
"minimum": 1
}
},
"additionalProperties": true,
"required": [
"partNumber"
]
}
HTTP 200 response (application/json)
{
"type": "object",
"properties": {
"upload": {
"type": "object",
"properties": {
"url": {
"type": "string"
},
"method": {
"const": "PUT"
},
"headers": {
"type": "object",
"properties": {},
"additionalProperties": true
},
"sizeBytes": {
"type": "integer",
"minimum": 0
}
},
"additionalProperties": true
}
},
"additionalProperties": true
}
Documented failures: 400, 401, 403, 404, 409, 500, 503.
/api/products/{id}/protected-content/uploads/{jobId}/complete
Verify completion of the private source upload
- Auth
- Account Bearer session token
- Scope
- Owned and assigned product. products.view for release listing, products.edit for private upload steps, products.publish for packaging/publication.
- Returns
- HTTP 200: job.
- Notes
- This marks source-upload completion. It does not yet publish an encrypted customer release. Current product management verifies workspace permissions and any product ownership/assignment before database writes or AI work. Creating a product or using untargeted new-product AI requires products.create and all-products scope. Existing-product edits/AI use products.edit, file operations use product_files permissions, scheduled-deal writes use marketing.manage, and purchase-option deal publication retains products.publish. Statistics require analytics.view. Publication/archival keep their dedicated permissions. The effective workspace developer owns new products; the teammate remains the audit actor.
Request, response and error reference
No request body fields are read by this operation.
HTTP 200 response (application/json)
{
"type": "object",
"properties": {
"job": {
"type": "object",
"properties": {
"id": {
"type": "string",
"pattern": "^[1-9][0-9]*$",
"description": "Opaque decimal upload-job identifier, not a content/release UUID."
},
"productId": {
"anyOf": [
{
"type": "integer",
"minimum": 1
},
{
"type": "null"
}
]
},
"sourceType": {
"type": "string"
},
"protectedContent": {
"type": "boolean"
},
"originalFilename": {
"type": "string"
},
"filename": {
"type": "string"
},
"storageKey": {
"type": "string"
},
"fileSizeBytes": {
"anyOf": [
{
"type": "integer",
"minimum": 0
},
{
"type": "null"
}
]
},
"expectedSizeBytes": {
"anyOf": [
{
"type": "integer",
"minimum": 0
},
{
"type": "null"
}
]
},
"mimeType": {
"type": "string"
},
"checksum": {
"type": "string"
},
"status": {
"type": "string"
},
"progress": {
"type": "integer",
"minimum": 0
},
"errorCode": {
"type": "string"
},
"errorMessage": {
"type": "string"
},
"attachedProductFileId": {
"type": "string"
},
"createdAt": {
"type": "string",
"format": "date-time"
},
"updatedAt": {
"type": "string",
"format": "date-time"
},
"completedAt": {
"anyOf": [
{
"type": "string",
"format": "date-time"
},
{
"type": "null"
}
]
},
"resumable": {
"type": "boolean"
},
"expiresAt": {
"anyOf": [
{
"type": "string",
"format": "date-time"
},
{
"type": "null"
}
]
}
},
"additionalProperties": true
}
},
"additionalProperties": true
}
Documented failures: 400, 401, 403, 404, 409, 500, 503.
/api/products/{id}/protected-content/uploads/{jobId}/publish
Package, sign and publish the completed protected archive
- Auth
- Account Bearer session token
- Scope
- Owned and assigned product. products.view for release listing, products.edit for private upload steps, products.publish for packaging/publication.
- Returns
- HTTP 200: contentId, releaseId, revision, packageHash.
- Notes
- Creates the immutable .sspc release in managed private storage. A repeated completed publication returns its existing release. A failed attempt preserves the private source for safe recovery; do not replace a raw source file with a public download fallback. Current product management verifies workspace permissions and any product ownership/assignment before database writes or AI work. Creating a product or using untargeted new-product AI requires products.create and all-products scope. Existing-product edits/AI use products.edit, file operations use product_files permissions, scheduled-deal writes use marketing.manage, and purchase-option deal publication retains products.publish. Statistics require analytics.view. Publication/archival keep their dedicated permissions. The effective workspace developer owns new products; the teammate remains the audit actor.
Request, response and error reference
No request body fields are read by this operation.
HTTP 200 response (application/json)
{
"type": "object",
"properties": {
"contentId": {
"type": "string",
"format": "uuid"
},
"releaseId": {
"type": "string",
"format": "uuid"
},
"revision": {
"type": "string"
},
"packageHash": {
"type": "string"
}
},
"additionalProperties": true
}
Documented failures: 400, 401, 403, 404, 409, 500, 503.
/api/delivery/protected-content
List compatible protected releases for an instrument
- Auth
- Account Bearer session token OR private customer-account token query fallback (prefer Bearer)
- Scope
- Signed-in customer-account identity and current permitted store, instrument and content ownership.
- Request fields
- query product_id: integer (required)
- query host_version: string (required)
- query token: string. Private customer-account session fallback. Prefer the Authorization header to avoid credentials in URLs.
- Returns
- HTTP 200: releases.
- Notes
- Requires a signed-in customer-account session: use Authorization: Bearer, or the supported private token query fallback. A legacy library/download token alone returns CUSTOMER_ACCOUNT_REQUIRED. Valid store-scoped sessions are limited to their own store; shared-account sessions retain their permitted store/product checks. Never publish token-bearing URLs. host_version is a software compatibility value, not a purchased-major restriction. A catalog entry or download URL does not authorize playback; verify the signed package and device permission in the SDK.
Request, response and error reference
Query and header parameters
[
{
"name": "product_id",
"in": "query",
"required": true,
"schema": {
"type": "integer",
"minimum": 1
}
},
{
"name": "host_version",
"in": "query",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "token",
"in": "query",
"required": false,
"schema": {
"type": "string"
},
"description": "Private customer-account session fallback. Prefer the Authorization header to avoid credentials in URLs."
}
]
No request body fields are read by this operation.
HTTP 200 response (application/json)
{
"type": "object",
"properties": {
"releases": {
"type": "array",
"items": {
"type": "object",
"properties": {
"contentId": {
"type": "string",
"format": "uuid"
},
"releaseId": {
"type": "string",
"format": "uuid"
},
"productId": {
"type": "integer",
"minimum": 1
},
"name": {
"type": "string"
},
"revision": {
"type": "string"
},
"status": {
"type": "string"
},
"owned": {
"type": "boolean"
},
"included": {
"type": "boolean"
},
"available": {
"type": "boolean"
},
"requiresParent": {
"type": "boolean"
},
"packageHash": {
"type": "string"
},
"manifest": {
"type": "object",
"properties": {
"alg": {
"const": "RS256"
},
"kid": {
"type": "string"
},
"payload": {
"type": "string"
},
"signature": {
"type": "string"
}
},
"additionalProperties": true,
"required": [
"alg",
"kid",
"payload",
"signature"
]
},
"downloadPath": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
}
},
"additionalProperties": true
}
}
},
"additionalProperties": true
}
Documented failures: 400, 401, 403, 404, 409, 500, 503.
Operation errors: CUSTOMER_ACCOUNT_REQUIRED, CUSTOMER_ACCOUNT_RESTRICTED, CUSTOMER_STORE_CLOSED, LIBRARY_SESSION_REVOKED, SESSION_VERIFICATION_UNAVAILABLE.
/api/delivery/protected-content/{releaseId}
Request a private protected-package link
- Auth
- Account Bearer session token OR private customer-account token query fallback (prefer Bearer)
- Scope
- Signed-in customer-account identity and current permitted store, instrument and content ownership.
- Request fields
- query product_id: integer (required)
- query host_version: string (required)
- query token: string. Private customer-account session fallback. Prefer the Authorization header to avoid credentials in URLs.
- Returns
- HTTP 200: url, filename, expiresIn, contentId, releaseId, packageHash.
- Notes
- Requires a signed-in customer-account session: use Authorization: Bearer, or the supported private token query fallback. A legacy library/download token alone returns CUSTOMER_ACCOUNT_REQUIRED. Valid store-scoped sessions are limited to their own store; shared-account sessions retain their permitted store/product checks. Never publish token-bearing URLs. host_version is a software compatibility value, not a purchased-major restriction. A catalog entry or download URL does not authorize playback; verify the signed package and device permission in the SDK.
Request, response and error reference
Query and header parameters
[
{
"name": "product_id",
"in": "query",
"required": true,
"schema": {
"type": "integer",
"minimum": 1
}
},
{
"name": "host_version",
"in": "query",
"required": true,
"schema": {
"type": "string"
}
},
{
"name": "token",
"in": "query",
"required": false,
"schema": {
"type": "string"
},
"description": "Private customer-account session fallback. Prefer the Authorization header to avoid credentials in URLs."
}
]
No request body fields are read by this operation.
HTTP 200 response (application/json)
{
"type": "object",
"properties": {
"url": {
"type": "string"
},
"filename": {
"type": "string"
},
"expiresIn": {
"type": "integer",
"minimum": 0
},
"contentId": {
"type": "string",
"format": "uuid"
},
"releaseId": {
"type": "string",
"format": "uuid"
},
"packageHash": {
"type": "string"
}
},
"additionalProperties": true
}
Documented failures: 400, 401, 403, 404, 409, 500, 503.
Operation errors: CUSTOMER_ACCOUNT_REQUIRED, CUSTOMER_ACCOUNT_RESTRICTED, CUSTOMER_STORE_CLOSED, LIBRARY_SESSION_REVOKED, SESSION_VERIFICATION_UNAVAILABLE.
/api/delivery/protected-content/products/{productId}/versions/{hostVersion}/releases/{releaseId}
Download a specific compatible protected release
- Auth
- Account Bearer session token OR private customer-account token query fallback (prefer Bearer)
- Scope
- Signed-in customer-account identity and current permitted instrument/content access.
- Request fields
- query token: string. Private customer-account session fallback. Prefer the Authorization header to avoid credentials in URLs.
- Returns
- HTTP 200: url, filename, expiresIn, contentId, releaseId, packageHash.
- Notes
- Requires a signed-in customer-account session: use Authorization: Bearer, or the supported private token query fallback. A legacy library/download token alone returns CUSTOMER_ACCOUNT_REQUIRED. Valid store-scoped sessions are limited to their own store; shared-account sessions retain their permitted store/product checks. Never publish token-bearing URLs.
Request, response and error reference
Query and header parameters
[
{
"name": "token",
"in": "query",
"required": false,
"schema": {
"type": "string"
},
"description": "Private customer-account session fallback. Prefer the Authorization header to avoid credentials in URLs."
}
]
No request body fields are read by this operation.
HTTP 200 response (application/json)
{
"type": "object",
"properties": {
"url": {
"type": "string"
},
"filename": {
"type": "string"
},
"expiresIn": {
"type": "integer",
"minimum": 0
},
"contentId": {
"type": "string",
"format": "uuid"
},
"releaseId": {
"type": "string",
"format": "uuid"
},
"packageHash": {
"type": "string"
}
},
"additionalProperties": true
}
Documented failures: 400, 401, 403, 404, 409, 500, 503.
Operation errors: CUSTOMER_ACCOUNT_REQUIRED, CUSTOMER_ACCOUNT_RESTRICTED, CUSTOMER_STORE_CLOSED, LIBRARY_SESSION_REVOKED, SESSION_VERIFICATION_UNAVAILABLE, CONTENT_ACCESS_REQUIRED, CONTENT_DELIVERY_NOT_READY, CONTENT_HOST_VERSION_REQUIRED.
/api/delivery/products/{productId}/versions/{versionId}/files/{fileIndex}
Deliver a current or retained product-version file
- Auth
- Account Bearer session token OR private customer-account token query fallback (prefer Bearer)
- Scope
- Signed-in customer-account identity and current product/store access. File index is zero-based.
- Request fields
- query token: string. Private customer-account session fallback. Prefer the Authorization header to avoid credentials in URLs.
- Returns
- HTTP 200: url, filename, expiresIn.
- Notes
- Requires a signed-in customer-account session: use Authorization: Bearer, or the supported private token query fallback. A legacy library/download token alone returns CUSTOMER_ACCOUNT_REQUIRED. Valid store-scoped sessions are limited to their own store; shared-account sessions retain their permitted store/product checks. Never publish token-bearing URLs. versionId accepts retained numeric/UUID versions and supported current/current-version identifiers. Software version does not create another paid ownership tier. application/json returns a private link; the default redirects with 302. Already issued links expire independently of later restrictions.
Request, response and error reference
Query and header parameters
[
{
"name": "token",
"in": "query",
"required": false,
"schema": {
"type": "string"
},
"description": "Private customer-account session fallback. Prefer the Authorization header to avoid credentials in URLs."
}
]
No request body fields are read by this operation.
HTTP 200 response (application/json)
{
"type": "object",
"properties": {
"url": {
"type": "string"
},
"filename": {
"type": "string"
},
"expiresIn": {
"type": "integer",
"minimum": 0
}
},
"additionalProperties": true
}
Documented failures: 400, 401, 403, 404, 409, 500, 503.
Operation errors: CUSTOMER_ACCOUNT_REQUIRED, CUSTOMER_ACCOUNT_RESTRICTED, CUSTOMER_STORE_CLOSED, LIBRARY_SESSION_REVOKED, SESSION_VERIFICATION_UNAVAILABLE.
/api/license/v1/protected-content
Read a protected catalog or request one release using activated native proof
- Auth
- x-ss-app-id + x-ss-plugin-key + x-ss-plugin-secret OR x-ss-app-id + x-ss-product-id + x-soundsync-public-client (matching generated native client)
- Scope
- Matching generated product identity plus a valid activated native device/session proof; no caller-selected customer authority.
- Request fields
- query host_version: string. Supported fallback when plugin_version and host_version are absent from JSON.
- query release_id: string. Supported fallback when release_id is absent from JSON.
- product_id: integer
- instance_id: string (required)
- device_credential: string
- content_protocol_version: 1 | 2
- plugin_session_id: string
- plugin_version: string
- host_version: string
- release_id: string
- Returns
- HTTP 200: review the response schema below.
- Notes
- Send instance_id. For device-credential authorization also send numeric content_protocol_version:2 (1 remains supported); device_credential alone does not select that branch. A valid plugin_session_id is the alternative activated proof. Send the real plugin_version or host_version; a host_version query fallback is supported. Omit release_id to list compatible releases; supply it for a private download. This catalog call is not activation and does not grant playback. SoundSync-wide customer suspension blocks new catalogs and download links. Store-only restrictions remain scoped to that store; product ownership is rechecked. Unavailable account verification fails closed with 503 SESSION_VERIFICATION_UNAVAILABLE. These online checks do not rewrite issued offline grants or change Access grace.
Request, response and error reference
Query and header parameters
[
{
"name": "host_version",
"in": "query",
"schema": {
"type": "string"
},
"description": "Supported fallback when plugin_version and host_version are absent from JSON."
},
{
"name": "release_id",
"in": "query",
"schema": {
"type": "string",
"format": "uuid"
},
"description": "Supported fallback when release_id is absent from JSON."
}
]
Request (application/json)
{
"type": "object",
"properties": {
"product_id": {
"type": "integer",
"minimum": 1
},
"instance_id": {
"type": "string",
"minLength": 1
},
"device_credential": {
"type": "string",
"minLength": 1
},
"content_protocol_version": {
"type": "integer",
"enum": [
1,
2
]
},
"plugin_session_id": {
"type": "string",
"minLength": 1
},
"plugin_version": {
"type": "string",
"minLength": 1
},
"host_version": {
"type": "string",
"minLength": 1
},
"release_id": {
"type": "string",
"format": "uuid"
}
},
"additionalProperties": true,
"required": [
"instance_id"
],
"anyOf": [
{
"required": [
"device_credential",
"content_protocol_version"
]
},
{
"required": [
"plugin_session_id"
]
}
]
}
HTTP 200 response (application/json)
{
"oneOf": [
{
"type": "object",
"properties": {
"releases": {
"type": "array",
"items": {
"type": "object",
"properties": {
"contentId": {
"type": "string",
"format": "uuid"
},
"releaseId": {
"type": "string",
"format": "uuid"
},
"productId": {
"type": "integer",
"minimum": 1
},
"name": {
"type": "string"
},
"revision": {
"type": "string"
},
"status": {
"type": "string"
},
"owned": {
"type": "boolean"
},
"included": {
"type": "boolean"
},
"available": {
"type": "boolean"
},
"requiresParent": {
"type": "boolean"
},
"packageHash": {
"type": "string"
},
"manifest": {
"type": "object",
"properties": {
"alg": {
"const": "RS256"
},
"kid": {
"type": "string"
},
"payload": {
"type": "string"
},
"signature": {
"type": "string"
}
},
"additionalProperties": true,
"required": [
"alg",
"kid",
"payload",
"signature"
]
},
"downloadPath": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
}
},
"additionalProperties": true
}
}
},
"additionalProperties": true,
"required": [
"releases"
]
},
{
"type": "object",
"properties": {
"url": {
"type": "string"
},
"filename": {
"type": "string"
},
"expiresIn": {
"type": "integer",
"minimum": 0
},
"contentId": {
"type": "string",
"format": "uuid"
},
"releaseId": {
"type": "string",
"format": "uuid"
},
"packageHash": {
"type": "string"
}
},
"additionalProperties": true,
"required": [
"url",
"filename",
"expiresIn",
"contentId",
"releaseId",
"packageHash"
]
}
]
}
Documented failures: 400, 401, 403, 404, 409, 500, 503.
Operation errors: CUSTOMER_ACCOUNT_RESTRICTED, SESSION_VERIFICATION_UNAVAILABLE, LIBRARY_USER_NOT_FOUND, library_customer_unavailable, CUSTOMER_STORE_CLOSED.
Use the identity for the route
The /api/delivery routes require a signed-in customer-account session, either shared or scoped to the relevant store. A legacy library/download token alone is not sufficient and returns CUSTOMER_ACCOUNT_REQUIRED. Prefer Authorization: Bearer instead of putting a private session in a URL.
The native /api/license/v1/protected-content call instead uses generated product identity and activated device/session proof. For device_credential send numeric content_protocol_version:2 as well as instance_id. A valid plugin_session_id is the alternate proof. Supply the real plugin_version or host_version for compatibility. Product credentials alone never authorize a customer download.
SoundSync
Read compatible releases with a customer-account session
curl --fail-with-body -sS --get "$SOUNDSYNC_API_BASE/api/delivery/protected-content" \
-H "Authorization: Bearer $SOUNDSYNC_CUSTOMER_TOKEN" \
--data-urlencode "product_id=$PRODUCT_ID" \
--data-urlencode "host_version=$HOST_VERSION"
SoundSync
Native device-credential request body
{
"product_id": 123,
"instance_id": "example-device",
"content_protocol_version": 2,
"device_credential": "ss_dc_AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
"plugin_version": "1.2.0"
}
SoundSync
Authorization boundaries
| Proof or response | Meaning |
|---|---|
| Product credentials | Identify the generated product. They do not select a customer or prove current ownership. |
| Signed-in customer-account identity | Required by these customer delivery routes. A legacy library token alone is rejected; store-specific sessions remain restricted to that store. |
| Native device credential or valid activated session | Binds a catalog request to the actual activated customer, product and instance. |
| Current account and store access | A SoundSync-wide suspension blocks new protected catalogs and download links, including native requests. A restriction at one store remains scoped to that store. If account status cannot be verified, the request fails closed with SESSION_VERIFICATION_UNAVAILABLE. |
| product_authorization / content_authorization | RS256 envelopes verified by the matching SDK; protocol 2 carries independent bank permissions. |
| protected_authorization_status: pending | Not permission to play. Keep the affected protected content locked until valid authorization is available. |
| Signed URL or catalog entry | A delivery capability or available item, not an audio-unlock instruction. Keep private URLs out of screenshots and logs. |
Download restrictions do not rewrite offline grants
These checks apply when requesting a new catalog or protected download link. They do not alter an already-issued signed offline grant, change the selected Access grace period or promise immediate recall of content already downloaded. Playback remains governed by the signed authorization verified by the matching package.
Compatibility is not another purchase
Compatible instrument majors and the minimum host version are software requirements. They do not limit a purchase to a paid major-version tier. The SDK reports missing product ownership separately from incompatible software.
Content authorization protocol 2 verifies and caches each bank permission independently. Up to 64 release references fit one server request; this is not a lifetime bank or library ceiling. The maintained client batches larger collections, normally in groups of 32.
Protected loading verifies integrity before use and as data is read. This raises the integration's enforcement strength; it is not a claim of piracy-proof software or instant remote revocation on disconnected devices.
SoundSync
Implementation
SoundSync
The protected archive controls
Set the release revision and software compatibility in the product editor. This example shows the upload form, not a completed publication or a playback authorization.
