API reference
Serials API
Endpoint reference for custom serial integration, customer redemption, serial generation, imports, exports, revocation, reassignment, and serial-linked downloads.
SoundSync
Serial inventory, redemption, and fulfillment calls
These calls cover both customer-facing serial redemption and developer-owned serial operations.
/api/serials/redeem
Redeem a serial from a customer-facing flow.
- Auth
- Account Bearer JWT
- Scope
- Product or storefront scoped
- Request fields
- serialCode: string (required)
- email: string (required)
- firstName: string
- lastName: string
- Returns
- Redemption result, customer/product context, and access/download next step.
- Side effects
- Can mark a serial redeemed and connect it to customer/product access.
- Notes
- Requires a verified signed-in checkout account and uses the current account-owned redemption service. Body email/names do not select or overwrite another customer identity. Use /api/library/redeem-serial for new clients.
Request, response and error reference
Legacy operation. Use the current scoped APIs for new integrations.
Request (application/json)
{
"type": "object",
"properties": {
"serialCode": {
"type": "string"
},
"email": {
"type": "string",
"format": "email"
},
"firstName": {
"type": "string"
},
"lastName": {
"type": "string"
}
},
"required": [
"serialCode",
"email"
],
"additionalProperties": true
}
HTTP 200 response (application/json)
{
"type": "object",
"properties": {
"message": {
"type": "string"
},
"serialCode": {
"type": "string"
}
},
"additionalProperties": true
}
Documented failures: 400, 500, 503.
/api/serials/available
List available serials for the signed-in developer.
- Auth
- Account Bearer JWT
- Scope
- Product or storefront scoped
- Request fields
- query search: string
- query dateRange: string
- Returns
- Grouped regular and promotion serial inventory by product or batch.
- Notes
- Legacy serial-table API, retained for existing clients. Use the current developer-scoped serial controls, customer-library redemption and product licensing API for new integrations. This path is not a replacement for the managed checkout, refund or payout APIs.
Request, response and error reference
Legacy operation. Use the current scoped APIs for new integrations.
Query and header parameters
[
{
"name": "search",
"in": "query",
"schema": {
"type": "string"
},
"required": false,
"description": ""
},
{
"name": "dateRange",
"in": "query",
"schema": {
"type": "string"
},
"required": false,
"description": ""
}
]
No request body fields are read by this operation.
HTTP 200 response (application/json)
{
"type": "object",
"properties": {
"regular": {
"type": "object",
"additionalProperties": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"minimum": 1
},
"code": {
"type": "string"
},
"product_id": {
"type": "integer",
"minimum": 1
},
"customer_id": {
"type": "integer",
"minimum": 1
},
"customer_email": {
"type": [
"string",
"null"
]
},
"redeemed": {
"type": "boolean"
},
"revoked": {
"type": "boolean"
},
"revoked_at": {
"type": [
"string",
"null"
],
"format": "date-time"
},
"redeemed_at": {
"type": [
"string",
"null"
],
"format": "date-time"
},
"download_count": {
"type": "integer"
},
"status": {
"type": "string"
}
},
"additionalProperties": true
}
}
},
"promos": {
"type": "object",
"additionalProperties": {
"type": "object",
"properties": {
"product_name": {
"type": "string"
},
"promo_price": {
"type": "number"
},
"serials": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"minimum": 1
},
"code": {
"type": "string"
},
"product_id": {
"type": "integer",
"minimum": 1
},
"customer_id": {
"type": "integer",
"minimum": 1
},
"customer_email": {
"type": [
"string",
"null"
]
},
"redeemed": {
"type": "boolean"
},
"revoked": {
"type": "boolean"
},
"revoked_at": {
"type": [
"string",
"null"
],
"format": "date-time"
},
"redeemed_at": {
"type": [
"string",
"null"
],
"format": "date-time"
},
"download_count": {
"type": "integer"
},
"status": {
"type": "string"
}
},
"additionalProperties": true
}
}
},
"additionalProperties": true
}
}
},
"additionalProperties": true
}
Documented failures: 400, 500, 503.
/api/serials/redeemed
List redeemed serials for the signed-in developer.
- Auth
- Account Bearer JWT
- Scope
- Product or storefront scoped
- Request fields
- query page: integer
- query search: string
- query dateRange: string
- Returns
- Rows with serial, customer, product, redemption date, status, revenue, and reseller labels.
- Notes
- Legacy serial-table API, retained for existing clients. Use the current developer-scoped serial controls, customer-library redemption and product licensing API for new integrations. This path is not a replacement for the managed checkout, refund or payout APIs.
Request, response and error reference
Legacy operation. Use the current scoped APIs for new integrations.
Query and header parameters
[
{
"name": "page",
"in": "query",
"schema": {
"type": "integer",
"minimum": 1
},
"required": false,
"description": ""
},
{
"name": "search",
"in": "query",
"schema": {
"type": "string"
},
"required": false,
"description": ""
},
{
"name": "dateRange",
"in": "query",
"schema": {
"type": "string"
},
"required": false,
"description": ""
}
]
No request body fields are read by this operation.
HTTP 200 response (application/json)
{
"type": "object",
"properties": {
"rows": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"minimum": 1
},
"code": {
"type": "string"
},
"product_id": {
"type": "integer",
"minimum": 1
},
"customer_id": {
"type": "integer",
"minimum": 1
},
"customer_email": {
"type": [
"string",
"null"
]
},
"redeemed": {
"type": "boolean"
},
"revoked": {
"type": "boolean"
},
"revoked_at": {
"type": [
"string",
"null"
],
"format": "date-time"
},
"redeemed_at": {
"type": [
"string",
"null"
],
"format": "date-time"
},
"download_count": {
"type": "integer"
},
"status": {
"type": "string"
}
},
"additionalProperties": true
}
},
"total": {
"type": "integer"
},
"page": {
"type": "integer"
},
"pageSize": {
"type": "integer"
}
},
"additionalProperties": true
}
Documented failures: 400, 500, 503.
/api/serials/generate
Generate serial inventory for a product.
- Auth
- Account Bearer JWT
- Scope
- Product or storefront scoped
- Request fields
- product_id: integer (required)
- quantity: integer
- prefix: string
- reseller_id: integer
- new_reseller_name: string
- expires_at: string,null
- promo_price: number
- promo_start: string,null
- promo_expires: string,null
- active_from: string,null
- active_to: string,null
- batch_tag: string
- notes: string
- Returns
- Generated serial batch summary.
- Side effects
- Creates new available serials and can create billable external redemption capacity usage later.
- Notes
- quantity defaults to 1; a supplied prefix must be exactly four alphanumeric characters. Reseller assignment requires an existing relationship.
Request, response and error reference
Legacy operation. Use the current scoped APIs for new integrations.
Request (application/json)
{
"type": "object",
"properties": {
"product_id": {
"type": "integer",
"minimum": 1
},
"quantity": {
"type": "integer",
"minimum": 1
},
"prefix": {
"type": "string"
},
"reseller_id": {
"type": "integer",
"minimum": 1
},
"new_reseller_name": {
"type": "string"
},
"expires_at": {
"type": [
"string",
"null"
],
"format": "date-time"
},
"promo_price": {
"type": "number"
},
"promo_start": {
"type": [
"string",
"null"
],
"format": "date-time"
},
"promo_expires": {
"type": [
"string",
"null"
],
"format": "date-time"
},
"active_from": {
"type": [
"string",
"null"
],
"format": "date-time"
},
"active_to": {
"type": [
"string",
"null"
],
"format": "date-time"
},
"batch_tag": {
"type": "string"
},
"notes": {
"type": "string"
}
},
"required": [
"product_id"
],
"additionalProperties": true
}
HTTP 201 response (application/json)
{
"type": "object",
"properties": {
"message": {
"type": "string"
},
"serials": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"minimum": 1
},
"code": {
"type": "string"
},
"product_id": {
"type": "integer",
"minimum": 1
},
"customer_id": {
"type": "integer",
"minimum": 1
},
"customer_email": {
"type": [
"string",
"null"
]
},
"redeemed": {
"type": "boolean"
},
"revoked": {
"type": "boolean"
},
"revoked_at": {
"type": [
"string",
"null"
],
"format": "date-time"
},
"redeemed_at": {
"type": [
"string",
"null"
],
"format": "date-time"
},
"download_count": {
"type": "integer"
},
"status": {
"type": "string"
}
},
"additionalProperties": true
}
}
},
"additionalProperties": true
}
Documented failures: 400, 500, 503.
/api/serials/import
Import serial inventory from CSV or file upload.
- Auth
- Account Bearer JWT
- Scope
- Product or storefront scoped
- Request fields
- serials: array (required)
- Returns
- Import summary and validation counts.
- Side effects
- Creates serial records under the developer product catalog.
- Notes
- JSON serial rows, not a file upload. Rows missing serialCode, email or productName, or without a matching product, can be skipped. This does not import provider payment authority or marketing consent.
Request, response and error reference
Legacy operation. Use the current scoped APIs for new integrations.
Request (application/json)
{
"type": "object",
"properties": {
"serials": {
"type": "array",
"items": {
"type": "object",
"properties": {
"firstName": {
"type": "string"
},
"lastName": {
"type": "string"
},
"email": {
"type": "string",
"format": "email"
},
"productName": {
"type": "string"
},
"serialCode": {
"type": "string"
},
"price": {
"type": "number"
},
"salePrice": {
"type": "number"
},
"downloadCount": {
"type": "integer"
},
"status": {
"type": "string"
},
"redeemDate": {
"type": [
"string",
"null"
],
"format": "date-time"
},
"date": {
"type": [
"string",
"null"
],
"format": "date-time"
}
},
"additionalProperties": true
}
}
},
"required": [
"serials"
],
"additionalProperties": true
}
HTTP 200 response (application/json)
{
"type": "object",
"properties": {
"success": {
"type": "boolean"
},
"count": {
"type": "integer"
}
},
"additionalProperties": true
}
Documented failures: 400, 500, 503.
/api/serials/export
Export serials as CSV for the signed-in developer.
- Auth
- Account Bearer JWT
- Scope
- Product or storefront scoped
- Returns
- CSV export of the developer serial inventory.
- Notes
- Legacy serial-table API, retained for existing clients. Use the current developer-scoped serial controls, customer-library redemption and product licensing API for new integrations. This path is not a replacement for the managed checkout, refund or payout APIs.
Request, response and error reference
Legacy operation. Use the current scoped APIs for new integrations.
No request body fields are read by this operation.
HTTP 200 response (text/csv)
{
"type": "string",
"format": "binary"
}
Documented failures: 400, 500, 503.
/api/serials/:id
Update a serial record.
- Auth
- Account Bearer JWT
- Scope
- serials.manage, the serial product owned by the effective developer workspace, and assigned product access. Foreign serial IDs are not available.
- Request fields
- action: revoke | reassign
- customer_email: string
- Returns
- Updated serial record or status summary.
- Notes
- Requires serials.manage, product ownership and assigned product scope. With no action, updates only an unlinked, unredeemed serial contact email. Changing a linked or redeemed customer identity returns 409 SERIAL_CUSTOMER_IDENTITY_LOCKED; use current customer information controls. reassign clears revocation; it does not redeem or transfer access.
Request, response and error reference
Legacy operation. Use the current scoped APIs for new integrations.
Request (application/json)
{
"type": "object",
"properties": {
"action": {
"type": "string",
"enum": [
"revoke",
"reassign"
]
},
"customer_email": {
"type": "string",
"format": "email"
}
},
"additionalProperties": true,
"anyOf": [
{
"required": [
"action"
]
},
{
"required": [
"customer_email"
]
}
]
}
HTTP 200 response (application/json)
{
"type": "object",
"properties": {
"id": {
"type": "integer",
"minimum": 1
},
"code": {
"type": "string"
},
"product_id": {
"type": "integer",
"minimum": 1
},
"customer_id": {
"type": "integer",
"minimum": 1
},
"customer_email": {
"type": [
"string",
"null"
]
},
"redeemed": {
"type": "boolean"
},
"revoked": {
"type": "boolean"
},
"revoked_at": {
"type": [
"string",
"null"
],
"format": "date-time"
},
"redeemed_at": {
"type": [
"string",
"null"
],
"format": "date-time"
},
"download_count": {
"type": "integer"
},
"status": {
"type": "string"
}
},
"additionalProperties": true
}
Documented failures: 400, 401, 403, 404, 409, 500, 503.
Operation errors: SERIAL_CUSTOMER_IDENTITY_LOCKED.
/api/serials/revoke/:id
Revoke a serial.
- Auth
- Account Bearer JWT
- Scope
- serials.manage, the serial product owned by the effective developer workspace, and assigned product access. Foreign serial IDs are not available.
- Returns
- Updated revoked serial/access state.
- Side effects
- Can remove or block customer access tied to the serial.
- Notes
- Legacy serial-table API, retained for existing clients. Use the current developer-scoped serial controls, customer-library redemption and product licensing API for new integrations. This path is not a replacement for the managed checkout, refund or payout APIs.
Request, response and error reference
Legacy operation. Use the current scoped APIs for new integrations.
No request body fields are read by this operation.
HTTP 200 response (application/json)
{
"type": "object",
"properties": {
"id": {
"type": "integer",
"minimum": 1
},
"code": {
"type": "string"
},
"product_id": {
"type": "integer",
"minimum": 1
},
"customer_id": {
"type": "integer",
"minimum": 1
},
"customer_email": {
"type": [
"string",
"null"
]
},
"redeemed": {
"type": "boolean"
},
"revoked": {
"type": "boolean"
},
"revoked_at": {
"type": [
"string",
"null"
],
"format": "date-time"
},
"redeemed_at": {
"type": [
"string",
"null"
],
"format": "date-time"
},
"download_count": {
"type": "integer"
},
"status": {
"type": "string"
}
},
"additionalProperties": true
}
Documented failures: 400, 500, 503.
/api/serials/reassign/:id
Clear revocation on a legacy serial
- Auth
- Account Bearer JWT
- Scope
- serials.manage, owned product and assigned product access. Compatibility restore only; use current developer-scoped controls for new integrations.
- Returns
- The serial row after revoked/revoked_at are cleared.
- Notes
- Despite the legacy name, this handler clears revoked/revoked_at; it does not accept or assign a different customer email. Use current scoped customer-access workflows for identity changes.
Request, response and error reference
Legacy operation. Use the current scoped APIs for new integrations.
No request body fields are read by this operation.
HTTP 200 response (application/json)
{
"type": "object",
"properties": {
"id": {
"type": "integer",
"minimum": 1
},
"code": {
"type": "string"
},
"product_id": {
"type": "integer",
"minimum": 1
},
"customer_id": {
"type": "integer",
"minimum": 1
},
"customer_email": {
"type": [
"string",
"null"
]
},
"redeemed": {
"type": "boolean"
},
"revoked": {
"type": "boolean"
},
"revoked_at": {
"type": [
"string",
"null"
],
"format": "date-time"
},
"redeemed_at": {
"type": [
"string",
"null"
],
"format": "date-time"
},
"download_count": {
"type": "integer"
},
"status": {
"type": "string"
}
},
"additionalProperties": true
}
Documented failures: 400, 500, 503.
/api/serials/refresh/:id
Reset legacy serial download tracking
- Auth
- Account Bearer JWT
- Scope
- serials.manage, the serial product owned by the effective developer workspace, and assigned product access. Foreign serial IDs are not available.
- Returns
- The updated serial row; download_count is reset.
- Side effects
- Resets download tracking and can create a legacy accounting charge. Not a harmless read or activation reset.
- Notes
- Returns the updated serial row after resetting download_count and download logs. Legacy refresh_logs accounting is also written; this is not an activation reset or ordinary validation. Do not use it as a customer self-service device reset or infer current pricing from this legacy route.
Request, response and error reference
Legacy operation. Use the current scoped APIs for new integrations.
No request body fields are read by this operation.
HTTP 200 response (application/json)
{
"type": "object",
"properties": {
"id": {
"type": "integer",
"minimum": 1
},
"code": {
"type": "string"
},
"product_id": {
"type": "integer",
"minimum": 1
},
"customer_id": {
"type": "integer",
"minimum": 1
},
"customer_email": {
"type": [
"string",
"null"
]
},
"redeemed": {
"type": "boolean"
},
"revoked": {
"type": "boolean"
},
"revoked_at": {
"type": [
"string",
"null"
],
"format": "date-time"
},
"redeemed_at": {
"type": [
"string",
"null"
],
"format": "date-time"
},
"download_count": {
"type": "integer"
},
"status": {
"type": "string"
}
},
"additionalProperties": true
}
Documented failures: 400, 500, 503.
/api/serials/download/:serialId
Serve an authorized serial-linked download.
- Auth
- Account Bearer JWT + private token query parameter
- Scope
- Product or storefront scoped
- Request fields
- query token: string (required)
- query file: string (required)
- Returns
- Authorized redirect to short-lived signed R2 delivery.
- Notes
- Requires serial/download context and signed-in owning customer. Only permitted managed files are signed.
Request, response and error reference
Legacy operation. Use the current scoped APIs for new integrations.
Query and header parameters
[
{
"name": "token",
"in": "query",
"schema": {
"type": "string"
},
"required": true,
"description": ""
},
{
"name": "file",
"in": "query",
"schema": {
"type": "string"
},
"required": true,
"description": ""
}
]
No request body fields are read by this operation.
HTTP 302 response headers
{
"Location": {
"schema": {
"type": "string",
"format": "uri"
},
"description": "Short-lived authorized private download URL."
}
}
Documented failures: 400, 500, 503.
/api/serials/download/increment
Check the legacy serial download allowance.
- Auth
- Account Bearer JWT
- Scope
- The customer account's owned, redeemed, non-revoked serial and its current product files.
- Request fields
- serial_id: integer (required)
- file_url: string
- Returns
- 200 JSON { allowed: boolean }. This check does not increment the counter.
- Notes
- Deprecated compatibility helper. Missing or foreign ownership is denied before reading counters or changing activity. Use entitlement delivery for new clients.
Request, response and error reference
Legacy operation. Use the current scoped APIs for new integrations.
Request (application/json)
{
"type": "object",
"properties": {
"serial_id": {
"type": "integer",
"minimum": 1
},
"file_url": {
"type": "string"
}
},
"required": [
"serial_id"
],
"additionalProperties": true
}
HTTP 200 response (application/json)
{
"type": "object",
"properties": {
"allowed": {
"type": "boolean"
}
},
"additionalProperties": true
}
Documented failures: 503.
/api/serials/download/confirm
Confirm successful serial download.
- Auth
- Account Bearer JWT
- Scope
- The customer account's owned, redeemed, non-revoked serial and its current product files.
- Request fields
- serial_id: integer (required)
- file_url: string (required)
- Returns
- 200 JSON { success: true } after recording download activity.
- Notes
- Deprecated compatibility helper. Missing or foreign ownership is denied before reading counters or changing activity. Use entitlement delivery for new clients.
Request, response and error reference
Legacy operation. Use the current scoped APIs for new integrations.
Request (application/json)
{
"type": "object",
"properties": {
"serial_id": {
"type": "integer",
"minimum": 1
},
"file_url": {
"type": "string"
}
},
"required": [
"serial_id",
"file_url"
],
"additionalProperties": true
}
HTTP 200 response (application/json)
{
"type": "object",
"properties": {
"success": {
"type": "boolean"
}
},
"additionalProperties": true
}
Documented failures: 503.
/api/serials/serials/download/confirm
Confirm through the legacy compatibility alias.
- Auth
- Account Bearer JWT
- Scope
- The customer account's owned, redeemed, non-revoked serial and its current product files.
- Request fields
- serial_id: integer (required)
- file_url: string (required)
- Returns
- 200 JSON { success: true } after recording download activity.
- Notes
- Deprecated compatibility helper. Missing or foreign ownership is denied before reading counters or changing activity. Use entitlement delivery for new clients.
Request, response and error reference
Legacy operation. Use the current scoped APIs for new integrations.
Request (application/json)
{
"type": "object",
"properties": {
"serial_id": {
"type": "integer",
"minimum": 1
},
"file_url": {
"type": "string"
}
},
"required": [
"serial_id",
"file_url"
],
"additionalProperties": true
}
HTTP 200 response (application/json)
{
"type": "object",
"properties": {
"success": {
"type": "boolean"
}
},
"additionalProperties": true
}
Documented failures: 503.
/api/serials/demo-csv
Download a demo CSV template for serial import.
- Auth
- Account Bearer JWT
- Scope
- Product or storefront scoped
- Returns
- CSV template.
- Notes
- Legacy serial-table API, retained for existing clients. Use the current developer-scoped serial controls, customer-library redemption and product licensing API for new integrations. This path is not a replacement for the managed checkout, refund or payout APIs.
Request, response and error reference
Legacy operation. Use the current scoped APIs for new integrations.
No request body fields are read by this operation.
HTTP 200 response (text/csv)
{
"type": "string",
"format": "binary"
}
Documented failures: 400, 500, 503.
/api/serials/transactions
List serial-related transactions.
- Auth
- Account Bearer JWT
- Scope
- Product or storefront scoped
- Request fields
- query page: integer
- Returns
- Transaction rows for serial/customer/product activity.
- Notes
- Legacy serial-table API, retained for existing clients. Use the current developer-scoped serial controls, customer-library redemption and product licensing API for new integrations. This path is not a replacement for the managed checkout, refund or payout APIs.
Request, response and error reference
Legacy operation. Use the current scoped APIs for new integrations.
Query and header parameters
[
{
"name": "page",
"in": "query",
"schema": {
"type": "integer",
"minimum": 1
},
"required": false,
"description": ""
}
]
No request body fields are read by this operation.
HTTP 200 response (application/json)
{
"type": "object",
"properties": {
"rows": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"minimum": 1
},
"status": {
"type": "string"
},
"created_at": {
"type": [
"string",
"null"
],
"format": "date-time"
},
"updated_at": {
"type": [
"string",
"null"
],
"format": "date-time"
}
},
"additionalProperties": true
}
},
"total": {
"type": "integer"
},
"page": {
"type": "integer"
},
"pageSize": {
"type": "integer"
}
},
"additionalProperties": true
}
Documented failures: 400, 500, 503.
/api/serials/customers-list
List customers for serial assignment and filtering.
- Auth
- Account Bearer JWT
- Scope
- Product or storefront scoped
- Returns
- Developer-scoped customer list.
- Notes
- Legacy serial-table API, retained for existing clients. Use the current developer-scoped serial controls, customer-library redemption and product licensing API for new integrations. This path is not a replacement for the managed checkout, refund or payout APIs.
Request, response and error reference
Legacy operation. Use the current scoped APIs for new integrations.
No request body fields are read by this operation.
HTTP 200 response (application/json)
{
"type": "object",
"properties": {
"rows": {
"type": "array",
"items": {
"type": "object",
"properties": {
"customer_email": {
"type": "string",
"format": "email"
},
"first_redemption": {
"type": [
"string",
"null"
],
"format": "date-time"
},
"latest_redemption": {
"type": [
"string",
"null"
],
"format": "date-time"
},
"product_count": {
"type": "integer"
},
"status": {
"type": "string"
}
},
"additionalProperties": true
}
}
},
"additionalProperties": true
}
Documented failures: 400, 500, 503.
/api/serials/resellers
List reseller/partner labels for serial workflows.
- Auth
- Account Bearer JWT
- Scope
- Product or storefront scoped
- Returns
- Developer-scoped reseller relationship list.
- Notes
- Legacy serial-table API, retained for existing clients. Use the current developer-scoped serial controls, customer-library redemption and product licensing API for new integrations. This path is not a replacement for the managed checkout, refund or payout APIs.
Request, response and error reference
Legacy operation. Use the current scoped APIs for new integrations.
No request body fields are read by this operation.
HTTP 200 response (application/json)
{
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"minimum": 1
},
"company_name": {
"type": "string"
},
"email": {
"type": "string",
"format": "email"
}
},
"additionalProperties": true
}
}
Documented failures: 400, 500, 503.
SoundSync
Serial state model
Serials can support direct sales, external/partner sales, HISE serial activation, and customer library access.
| State | Meaning |
|---|---|
| Available | Serial exists and has not been redeemed. |
| Redeemed | Serial has been connected to a customer/product context. |
| Revoked | Serial should no longer authorize access. |
| Restored | Revocation was cleared by an authorized developer. The legacy reassign action does not change the customer, redeem a serial, or transfer ownership. |
Current delivery versus legacy download helpers
Use the entitlement-delivery and customer-library flows for new integrations. Deprecated serial download counters and confirmation helpers now require a signed-in customer account, an owned active serial, and, for confirmation, a file belonging to its product. They record/check download activity; they do not authorize file access.
Keep customer-account tokens, library/download links, private serial download tokens, and public download codes distinct. Invoice access and review submission require the supported customer-account identity, not an arbitrary shared library link. Follow the authentication and product checks for the actual file request.
