Skip to content
SoundSyncAudio software platform

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

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

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

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

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

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

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

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

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

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

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

Read-only catalog request; do not use a legacy library token
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

Illustrative proof only; use the private credential returned by your activation
{
  "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 responseMeaning
Product credentialsIdentify the generated product. They do not select a customer or prove current ownership.
Signed-in customer-account identityRequired 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 sessionBinds a catalog request to the actual activated customer, product and instance.
Current account and store accessA 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_authorizationRS256 envelopes verified by the matching SDK; protocol 2 carries independent bank permissions.
protected_authorization_status: pendingNot permission to play. Keep the affected protected content locked until valid authorization is available.
Signed URL or catalog entryA 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

Protected-content guide

Upload and host integration.

Native licensing

Activation and validation response extensions.

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.

Example protected archive setup in the actual product editor. Uploading and publishing remain separate steps.