API reference
Licensing Rules, Delivery Versions and Activity API
Manage product licensing policy, versioned delivery, connection diagnostics and abandoned-checkout reminder settings.
Change licensing policy deliberately
Read licensing-rules for the assigned product, then send the full intended rule set when saving. The GET can initialize a missing rule row. PUT uses service defaults for omitted values, not sparse-patch semantics. Preserve the current fields and include expectedRules when detecting concurrent edits matters; a stale snapshot returns LICENSE_RULES_CHANGED.
Rules cover serial-only, email-entitlement or combined activation, offline-grace settings, activation limits, customer reset policy and supported invalid/refunded/suspended behavior. These configure policy; they do not establish native runtime proof for every package or grant a customer entitlement.
SoundSync
Read before editing
curl --fail-with-body -sS "$SOUNDSYNC_API_BASE/api/developer/products/123/licensing-rules" \
-H "Authorization: Bearer $DEVELOPER_TOKEN"
A delivery version is not an upload
Create versions with a version label, release copy, active/published flags and supported asset metadata. Use the managed upload workflow before referencing files. Creation and latest selection return the refreshed versions list. The latest action activates the selected version and removes the previous latest marker only within that product.
File keys and delivery URLs can be private. Version metadata does not validate a file, grant a download or change existing ownership. Reload the current list rather than assuming array positions or historical IDs still identify the intended release.
Connection history and online presence differ
The status endpoint combines connection tests with server-recorded successful activation and validation events. JUCE does not need a manual connection-test record when licensing activity is already recorded. Missing history on published products is informational and does not lower readiness.
Recent evidence means success within the past 24 hours associated with a current active product credential, excluding explicitly non-production activity. Existing server-side licensing events without an environment marker are recognized; manual tests require a production/live marker. evidenceState distinguishes recent_runtime, recent_test, historical, credential_unverified and not_recorded. Only recentRuntimeSuccess describes a recent successful licensing request. An old, non-production or revoked-credential record is not current health, and no historical result is a real-time heartbeat. Private diagnostic events remain available through plugin-connections.
Activity uses camelCase fields; connection records use database-style names. Raw bigint identifiers can be decimal strings. Preserve their exact value instead of converting them to floating-point numbers. These reports may contain customer names, email addresses and serials; keep responses private and redact screenshots.
Reminder settings do not send a campaign
Abandoned-checkout settings are developer-wide, even when an owned product is supplied as context. Delegated team calls should provide an assigned productId to select the owning developer. A save configures enabled and a delay of 1 to 168 hours; it does not guarantee delivery or bypass suppression and audience rules.
SoundSync
Continue the workflow
SoundSync
Requests and responses
/api/developer/products/{productId}/licensing-rules
Read or initialize product licensing rules
- Auth
- Account Bearer JWT
- Scope
- products.view and assigned-product access.
- Returns
- HTTP 200: rules.
- Notes
- This read upserts the product rule row and can initialize defaults. It is not a zero-write health check.
Request, response and error reference
No request body fields are read by this operation.
HTTP 200 response (application/json)
{
"type": "object",
"properties": {
"rules": {
"type": "object",
"properties": {
"id": {
"anyOf": [
{
"type": "integer",
"minimum": 1
},
{
"type": "string",
"pattern": "^[1-9][0-9]*$"
}
],
"description": "A positive identifier. PostgreSQL bigint fields can be decimal strings; preserve them without lossy numeric conversion."
},
"developerId": {
"type": "integer",
"minimum": 1
},
"productId": {
"type": "integer",
"minimum": 1
},
"activationMode": {
"type": "string",
"enum": [
"serial_only",
"email_entitlement",
"serial_or_email"
]
},
"offlineGraceEnabled": {
"type": "boolean"
},
"offlineGraceDays": {
"type": "integer",
"minimum": 0,
"maximum": 90
},
"maxActivationsPerCustomer": {
"type": [
"integer",
"null"
],
"minimum": 1,
"maximum": 100
},
"allowCustomerSelfReset": {
"type": "boolean"
},
"resetCooldownDays": {
"type": [
"integer",
"null"
],
"minimum": 0,
"maximum": 365
},
"suspendedLicenseBehavior": {
"type": "string",
"enum": [
"lock",
"warning_only",
"grace"
]
},
"refundedOrderBehavior": {
"type": "string",
"enum": [
"revoke_immediately",
"suspend",
"manual_review"
]
},
"failedValidationBehavior": {
"type": "string",
"enum": [
"show_activation_screen",
"show_support_message",
"lock"
]
},
"createdAt": {
"type": [
"string",
"null"
],
"format": "date-time"
},
"updatedAt": {
"type": [
"string",
"null"
],
"format": "date-time"
}
},
"additionalProperties": true
}
},
"additionalProperties": true
}
Documented failures: 400, 401, 403, 404, 409, 500, 503.
/api/developer/products/{productId}/licensing-rules
Save licensing rules and detect stale edits
- Auth
- Account Bearer JWT
- Scope
- products.edit and assigned-product access.
- Request fields
- activationMode: serial_only | email_entitlement | serial_or_email
- offlineGraceEnabled: boolean
- offlineGraceDays: integer
- maxActivationsPerCustomer: integer,null
- allowCustomerSelfReset: boolean
- resetCooldownDays: integer,null
- suspendedLicenseBehavior: lock | warning_only | grace
- refundedOrderBehavior: revoke_immediately | suspend | manual_review
- failedValidationBehavior: show_activation_screen | show_support_message | lock
- expectedRules: object
- Returns
- HTTP 200: rules.
- Notes
- Send the full intended rule set. Unlike a sparse PATCH, omitted fields normalize to service defaults: serial_or_email, offline grace enabled for 7 days, no explicit activation limit, self-reset off, reset cooldown 30 days, lock suspended licenses, immediate refund revocation and activation screen on failure. Snake_case field aliases are accepted. If expectedRules is supplied, include every current rule field; a mismatch returns 409 LICENSE_RULES_CHANGED. Stored rules do not prove every native runtime state has been exercised.
Request, response and error reference
Request (application/json)
{
"type": "object",
"properties": {
"activationMode": {
"type": "string",
"enum": [
"serial_only",
"email_entitlement",
"serial_or_email"
]
},
"offlineGraceEnabled": {
"type": "boolean"
},
"offlineGraceDays": {
"type": "integer",
"minimum": 0,
"maximum": 90
},
"maxActivationsPerCustomer": {
"type": [
"integer",
"null"
],
"minimum": 1,
"maximum": 100
},
"allowCustomerSelfReset": {
"type": "boolean"
},
"resetCooldownDays": {
"type": [
"integer",
"null"
],
"minimum": 0,
"maximum": 365
},
"suspendedLicenseBehavior": {
"type": "string",
"enum": [
"lock",
"warning_only",
"grace"
]
},
"refundedOrderBehavior": {
"type": "string",
"enum": [
"revoke_immediately",
"suspend",
"manual_review"
]
},
"failedValidationBehavior": {
"type": "string",
"enum": [
"show_activation_screen",
"show_support_message",
"lock"
]
},
"expectedRules": {
"type": "object",
"properties": {
"activationMode": {
"type": "string",
"enum": [
"serial_only",
"email_entitlement",
"serial_or_email"
]
},
"offlineGraceEnabled": {
"type": "boolean"
},
"offlineGraceDays": {
"type": "integer",
"minimum": 0,
"maximum": 90
},
"maxActivationsPerCustomer": {
"type": [
"integer",
"null"
],
"minimum": 1,
"maximum": 100
},
"allowCustomerSelfReset": {
"type": "boolean"
},
"resetCooldownDays": {
"type": [
"integer",
"null"
],
"minimum": 0,
"maximum": 365
},
"suspendedLicenseBehavior": {
"type": "string",
"enum": [
"lock",
"warning_only",
"grace"
]
},
"refundedOrderBehavior": {
"type": "string",
"enum": [
"revoke_immediately",
"suspend",
"manual_review"
]
},
"failedValidationBehavior": {
"type": "string",
"enum": [
"show_activation_screen",
"show_support_message",
"lock"
]
}
},
"additionalProperties": true
}
},
"additionalProperties": true
}
HTTP 200 response (application/json)
{
"type": "object",
"properties": {
"rules": {
"type": "object",
"properties": {
"id": {
"anyOf": [
{
"type": "integer",
"minimum": 1
},
{
"type": "string",
"pattern": "^[1-9][0-9]*$"
}
],
"description": "A positive identifier. PostgreSQL bigint fields can be decimal strings; preserve them without lossy numeric conversion."
},
"developerId": {
"type": "integer",
"minimum": 1
},
"productId": {
"type": "integer",
"minimum": 1
},
"activationMode": {
"type": "string",
"enum": [
"serial_only",
"email_entitlement",
"serial_or_email"
]
},
"offlineGraceEnabled": {
"type": "boolean"
},
"offlineGraceDays": {
"type": "integer",
"minimum": 0,
"maximum": 90
},
"maxActivationsPerCustomer": {
"type": [
"integer",
"null"
],
"minimum": 1,
"maximum": 100
},
"allowCustomerSelfReset": {
"type": "boolean"
},
"resetCooldownDays": {
"type": [
"integer",
"null"
],
"minimum": 0,
"maximum": 365
},
"suspendedLicenseBehavior": {
"type": "string",
"enum": [
"lock",
"warning_only",
"grace"
]
},
"refundedOrderBehavior": {
"type": "string",
"enum": [
"revoke_immediately",
"suspend",
"manual_review"
]
},
"failedValidationBehavior": {
"type": "string",
"enum": [
"show_activation_screen",
"show_support_message",
"lock"
]
},
"createdAt": {
"type": [
"string",
"null"
],
"format": "date-time"
},
"updatedAt": {
"type": [
"string",
"null"
],
"format": "date-time"
}
},
"additionalProperties": true
}
},
"additionalProperties": true
}
Documented failures: 400, 401, 403, 404, 409, 500, 503.
/api/developer/activity
Read workspace activity
- Auth
- Account Bearer JWT
- Scope
- analytics.view and all-products scope.
- Request fields
- query limit: integer
- query eventType: string
- Returns
- HTTP 200: events.
- Notes
- Customer identity requires customers.view; serials require serials.view; order IDs require orders.view; entitlement IDs require entitlements.view. Restricted fields are null. Opaque messages, actor details and nested metadata require all four record permissions plus refunds.view. Client query/body fields cannot grant permissions.
Request, response and error reference
Query and header parameters
[
{
"name": "limit",
"in": "query",
"schema": {
"type": "integer",
"minimum": 1,
"maximum": 100,
"default": 25
},
"required": false,
"description": ""
},
{
"name": "eventType",
"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": {
"events": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"anyOf": [
{
"type": "integer",
"minimum": 1
},
{
"type": "string",
"pattern": "^[1-9][0-9]*$"
}
],
"description": "A positive identifier. PostgreSQL bigint fields can be decimal strings; preserve them without lossy numeric conversion."
},
"developerId": {
"type": "integer",
"minimum": 1
},
"actorType": {
"type": [
"string",
"null"
]
},
"actorUserId": {
"type": [
"integer",
"null"
]
},
"customerId": {
"type": [
"integer",
"null"
]
},
"customerEmail": {
"type": [
"string",
"null"
]
},
"customerName": {
"type": [
"string",
"null"
]
},
"productId": {
"type": [
"integer",
"null"
]
},
"productName": {
"type": [
"string",
"null"
]
},
"serialId": {
"type": [
"integer",
"null"
]
},
"serialCode": {
"type": [
"string",
"null"
]
},
"entitlementId": {
"anyOf": [
{
"anyOf": [
{
"type": "integer",
"minimum": 1
},
{
"type": "string",
"pattern": "^[1-9][0-9]*$"
}
],
"description": "A positive identifier. PostgreSQL bigint fields can be decimal strings; preserve them without lossy numeric conversion."
},
{
"type": "null"
}
]
},
"orderId": {
"anyOf": [
{
"anyOf": [
{
"type": "integer",
"minimum": 1
},
{
"type": "string",
"pattern": "^[1-9][0-9]*$"
}
],
"description": "A positive identifier. PostgreSQL bigint fields can be decimal strings; preserve them without lossy numeric conversion."
},
{
"type": "null"
}
]
},
"eventType": {
"type": "string"
},
"severity": {
"type": "string"
},
"message": {
"type": [
"string",
"null"
]
},
"createdAt": {
"type": [
"string",
"null"
],
"format": "date-time"
},
"metadata": {
"type": "object",
"additionalProperties": true,
"description": "Operation-specific extension data; do not put credentials or unnecessary personal information here."
}
},
"additionalProperties": true
}
}
},
"additionalProperties": true
}
Documented failures: 400, 401, 403, 404, 409, 500, 503.
/api/developer/products/{productId}/activity
Read activity for an assigned product
- Auth
- Account Bearer JWT
- Scope
- analytics.view and assigned-product access.
- Request fields
- query limit: integer
- Returns
- HTTP 200: events.
- Notes
- Also ensures the product licensing-rule row. Customer identity requires customers.view; serials require serials.view; order IDs require orders.view; entitlement IDs require entitlements.view. Restricted fields are null. Opaque messages, actor details and nested metadata require all four record permissions plus refunds.view. Client query/body fields cannot grant permissions.
Request, response and error reference
Query and header parameters
[
{
"name": "limit",
"in": "query",
"schema": {
"type": "integer",
"minimum": 1,
"maximum": 100,
"default": 25
},
"required": false,
"description": ""
}
]
No request body fields are read by this operation.
HTTP 200 response (application/json)
{
"type": "object",
"properties": {
"events": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"anyOf": [
{
"type": "integer",
"minimum": 1
},
{
"type": "string",
"pattern": "^[1-9][0-9]*$"
}
],
"description": "A positive identifier. PostgreSQL bigint fields can be decimal strings; preserve them without lossy numeric conversion."
},
"developerId": {
"type": "integer",
"minimum": 1
},
"actorType": {
"type": [
"string",
"null"
]
},
"actorUserId": {
"type": [
"integer",
"null"
]
},
"customerId": {
"type": [
"integer",
"null"
]
},
"customerEmail": {
"type": [
"string",
"null"
]
},
"customerName": {
"type": [
"string",
"null"
]
},
"productId": {
"type": [
"integer",
"null"
]
},
"productName": {
"type": [
"string",
"null"
]
},
"serialId": {
"type": [
"integer",
"null"
]
},
"serialCode": {
"type": [
"string",
"null"
]
},
"entitlementId": {
"anyOf": [
{
"anyOf": [
{
"type": "integer",
"minimum": 1
},
{
"type": "string",
"pattern": "^[1-9][0-9]*$"
}
],
"description": "A positive identifier. PostgreSQL bigint fields can be decimal strings; preserve them without lossy numeric conversion."
},
{
"type": "null"
}
]
},
"orderId": {
"anyOf": [
{
"anyOf": [
{
"type": "integer",
"minimum": 1
},
{
"type": "string",
"pattern": "^[1-9][0-9]*$"
}
],
"description": "A positive identifier. PostgreSQL bigint fields can be decimal strings; preserve them without lossy numeric conversion."
},
{
"type": "null"
}
]
},
"eventType": {
"type": "string"
},
"severity": {
"type": "string"
},
"message": {
"type": [
"string",
"null"
]
},
"createdAt": {
"type": [
"string",
"null"
],
"format": "date-time"
},
"metadata": {
"type": "object",
"additionalProperties": true,
"description": "Operation-specific extension data; do not put credentials or unnecessary personal information here."
}
},
"additionalProperties": true
}
}
},
"additionalProperties": true
}
Documented failures: 400, 401, 403, 404, 409, 500, 503.
/api/developer/products/{productId}/file-versions
List versioned delivery metadata
- Auth
- Account Bearer JWT
- Scope
- product_files.view and assigned-product access.
- Returns
- HTTP 200: versions.
Request, response and error reference
No request body fields are read by this operation.
HTTP 200 response (application/json)
{
"type": "object",
"properties": {
"versions": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"anyOf": [
{
"type": "integer",
"minimum": 1
},
{
"type": "string",
"pattern": "^[1-9][0-9]*$"
}
],
"description": "A positive identifier. PostgreSQL bigint fields can be decimal strings; preserve them without lossy numeric conversion."
},
"productId": {
"type": "integer",
"minimum": 1
},
"version": {
"type": "string"
},
"releaseTitle": {
"type": [
"string",
"null"
]
},
"releaseNotes": {
"type": [
"string",
"null"
]
},
"isActive": {
"type": "boolean"
},
"isLatest": {
"type": "boolean"
},
"published": {
"type": "boolean"
},
"assets": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"anyOf": [
{
"type": "integer",
"minimum": 1
},
{
"type": "string",
"pattern": "^[1-9][0-9]*$"
}
],
"description": "A positive identifier. PostgreSQL bigint fields can be decimal strings; preserve them without lossy numeric conversion."
},
"fileName": {
"type": "string"
},
"url": {
"type": [
"string",
"null"
]
},
"fileKey": {
"type": [
"string",
"null"
]
},
"fileSize": {
"type": [
"number",
"string",
"null"
]
},
"mimeType": {
"type": [
"string",
"null"
]
},
"platform": {
"type": [
"string",
"null"
]
},
"sortOrder": {
"type": "integer"
},
"createdAt": {
"type": [
"string",
"null"
],
"format": "date-time"
}
},
"additionalProperties": true
}
},
"createdAt": {
"type": [
"string",
"null"
],
"format": "date-time"
},
"updatedAt": {
"type": [
"string",
"null"
],
"format": "date-time"
}
},
"additionalProperties": true
}
}
},
"additionalProperties": true
}
Documented failures: 400, 401, 403, 404, 409, 500, 503.
/api/developer/products/{productId}/file-versions
Create versioned delivery metadata
- Auth
- Account Bearer JWT
- Scope
- product_files.manage and assigned-product access.
- Request fields
- version: string (required)
- releaseTitle: string
- releaseNotes: string
- isActive: boolean
- isLatest: boolean
- published: boolean
- assets: array
- Returns
- HTTP 201: versions.
- Notes
- Returns the refreshed version list, not a single version. isActive and published default true; isLatest defaults false. Making a version latest clears the previous latest within this product. Asset entries are metadata, not an upload or proof that a URL is safe or publicly accessible. Use the upload workflow first and do not publish private storage keys.
Request, response and error reference
Request (application/json)
{
"type": "object",
"properties": {
"version": {
"type": "string"
},
"releaseTitle": {
"type": "string"
},
"releaseNotes": {
"type": "string"
},
"isActive": {
"type": "boolean"
},
"isLatest": {
"type": "boolean"
},
"published": {
"type": "boolean"
},
"assets": {
"type": "array",
"items": {
"type": "object",
"properties": {
"fileName": {
"type": "string"
},
"url": {
"type": "string"
},
"fileKey": {
"type": "string"
},
"fileSize": {
"type": [
"number",
"string",
"null"
]
},
"mimeType": {
"type": "string"
},
"platform": {
"type": "string"
},
"sortOrder": {
"type": "integer"
}
},
"additionalProperties": true
}
}
},
"required": [
"version"
],
"additionalProperties": true
}
HTTP 201 response (application/json)
{
"type": "object",
"properties": {
"versions": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"anyOf": [
{
"type": "integer",
"minimum": 1
},
{
"type": "string",
"pattern": "^[1-9][0-9]*$"
}
],
"description": "A positive identifier. PostgreSQL bigint fields can be decimal strings; preserve them without lossy numeric conversion."
},
"productId": {
"type": "integer",
"minimum": 1
},
"version": {
"type": "string"
},
"releaseTitle": {
"type": [
"string",
"null"
]
},
"releaseNotes": {
"type": [
"string",
"null"
]
},
"isActive": {
"type": "boolean"
},
"isLatest": {
"type": "boolean"
},
"published": {
"type": "boolean"
},
"assets": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"anyOf": [
{
"type": "integer",
"minimum": 1
},
{
"type": "string",
"pattern": "^[1-9][0-9]*$"
}
],
"description": "A positive identifier. PostgreSQL bigint fields can be decimal strings; preserve them without lossy numeric conversion."
},
"fileName": {
"type": "string"
},
"url": {
"type": [
"string",
"null"
]
},
"fileKey": {
"type": [
"string",
"null"
]
},
"fileSize": {
"type": [
"number",
"string",
"null"
]
},
"mimeType": {
"type": [
"string",
"null"
]
},
"platform": {
"type": [
"string",
"null"
]
},
"sortOrder": {
"type": "integer"
},
"createdAt": {
"type": [
"string",
"null"
],
"format": "date-time"
}
},
"additionalProperties": true
}
},
"createdAt": {
"type": [
"string",
"null"
],
"format": "date-time"
},
"updatedAt": {
"type": [
"string",
"null"
],
"format": "date-time"
}
},
"additionalProperties": true
}
}
},
"additionalProperties": true
}
Documented failures: 400, 401, 403, 404, 409, 500, 503.
/api/developer/products/{productId}/file-versions/{versionId}/latest
Select the latest delivery version
- Auth
- Account Bearer JWT
- Scope
- product_files.manage and assigned-product access.
- Returns
- HTTP 200: versions.
- Notes
- The version must belong to this product/developer. Marks it active and clears other latest markers; does not upload files or change customer ownership.
Request, response and error reference
No request body fields are read by this operation.
HTTP 200 response (application/json)
{
"type": "object",
"properties": {
"versions": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"anyOf": [
{
"type": "integer",
"minimum": 1
},
{
"type": "string",
"pattern": "^[1-9][0-9]*$"
}
],
"description": "A positive identifier. PostgreSQL bigint fields can be decimal strings; preserve them without lossy numeric conversion."
},
"productId": {
"type": "integer",
"minimum": 1
},
"version": {
"type": "string"
},
"releaseTitle": {
"type": [
"string",
"null"
]
},
"releaseNotes": {
"type": [
"string",
"null"
]
},
"isActive": {
"type": "boolean"
},
"isLatest": {
"type": "boolean"
},
"published": {
"type": "boolean"
},
"assets": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"anyOf": [
{
"type": "integer",
"minimum": 1
},
{
"type": "string",
"pattern": "^[1-9][0-9]*$"
}
],
"description": "A positive identifier. PostgreSQL bigint fields can be decimal strings; preserve them without lossy numeric conversion."
},
"fileName": {
"type": "string"
},
"url": {
"type": [
"string",
"null"
]
},
"fileKey": {
"type": [
"string",
"null"
]
},
"fileSize": {
"type": [
"number",
"string",
"null"
]
},
"mimeType": {
"type": [
"string",
"null"
]
},
"platform": {
"type": [
"string",
"null"
]
},
"sortOrder": {
"type": "integer"
},
"createdAt": {
"type": [
"string",
"null"
],
"format": "date-time"
}
},
"additionalProperties": true
}
},
"createdAt": {
"type": [
"string",
"null"
],
"format": "date-time"
},
"updatedAt": {
"type": [
"string",
"null"
],
"format": "date-time"
}
},
"additionalProperties": true
}
}
},
"additionalProperties": true
}
Documented failures: 400, 401, 403, 404, 409, 500, 503.
/api/developer/products/{productId}/plugin-connections
Read private product connection events
- Auth
- Account Bearer JWT
- Scope
- credentials.view and assigned-product access.
- Request fields
- query limit: integer
- Returns
- HTTP 200: connections.
- Notes
- Also ensures licensing rules. Rows use event_kind, status and plugin_version; event_type is not the connection-event field. Customer identity, device_hash and engagement_signal_id are null without customers.view; serial_id/serial_code are null without serials.view. Opaque failure_reason and metadata require both permissions, otherwise null/{}. Credential access alone does not grant private customer or serial data. Client filters cannot grant permissions.
Request, response and error reference
Query and header parameters
[
{
"name": "limit",
"in": "query",
"schema": {
"type": "integer",
"minimum": 1,
"maximum": 100,
"default": 25
},
"required": false,
"description": ""
}
]
No request body fields are read by this operation.
HTTP 200 response (application/json)
{
"type": "object",
"properties": {
"connections": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"anyOf": [
{
"type": "integer",
"minimum": 1
},
{
"type": "string",
"pattern": "^[1-9][0-9]*$"
}
],
"description": "A positive identifier. PostgreSQL bigint fields can be decimal strings; preserve them without lossy numeric conversion."
},
"developer_id": {
"type": "integer",
"minimum": 1
},
"customer_id": {
"type": [
"integer",
"null"
]
},
"product_id": {
"type": "integer",
"minimum": 1
},
"serial_id": {
"type": [
"integer",
"null"
]
},
"developer_customer_id": {
"anyOf": [
{
"anyOf": [
{
"type": "integer",
"minimum": 1
},
{
"type": "string",
"pattern": "^[1-9][0-9]*$"
}
],
"description": "A positive identifier. PostgreSQL bigint fields can be decimal strings; preserve them without lossy numeric conversion."
},
{
"type": "null"
}
]
},
"key_id": {
"anyOf": [
{
"anyOf": [
{
"type": "integer",
"minimum": 1
},
{
"type": "string",
"pattern": "^[1-9][0-9]*$"
}
],
"description": "A positive identifier. PostgreSQL bigint fields can be decimal strings; preserve them without lossy numeric conversion."
},
{
"type": "null"
}
]
},
"engagement_signal_id": {
"anyOf": [
{
"anyOf": [
{
"type": "integer",
"minimum": 1
},
{
"type": "string",
"pattern": "^[1-9][0-9]*$"
}
],
"description": "A positive identifier. PostgreSQL bigint fields can be decimal strings; preserve them without lossy numeric conversion."
},
{
"type": "null"
}
]
},
"event_kind": {
"type": "string"
},
"status": {
"type": "string"
},
"plugin_version": {
"type": [
"string",
"null"
]
},
"environment": {
"type": [
"string",
"null"
]
},
"device_hash": {
"type": [
"string",
"null"
]
},
"failure_reason": {
"type": [
"string",
"null"
]
},
"product_name": {
"type": [
"string",
"null"
]
},
"customer_email": {
"type": [
"string",
"null"
]
},
"serial_code": {
"type": [
"string",
"null"
]
},
"created_at": {
"type": [
"string",
"null"
],
"format": "date-time"
},
"metadata": {
"type": "object",
"additionalProperties": true,
"description": "Operation-specific extension data; do not put credentials or unnecessary personal information here."
}
},
"additionalProperties": true
}
}
},
"additionalProperties": true
}
Documented failures: 400, 401, 403, 404, 409, 500, 503.
/api/developer/plugin-connections/products/{productId}/status
Read product connection and licensing evidence
- Auth
- Account Bearer JWT
- Scope
- credentials.view and assigned-product access.
- Returns
- HTTP 200: ok, productId, connected, status, lastSeenAt, lastSuccessAt, pluginVersion, environment, credentialId, errorCode, errorReason, evidenceState, evidenceSource, setupVerified, recentRuntimeSuccess, currentCredential, historicalSuccess, recentWindowHours, healthStatus, message.
- Notes
- Reads Test Connection history and server-recorded successful activation/validation events. Runtime evidence must match the owning product/developer and an active, non-revoked product credential. connected means eligible success within the past 24 hours with that credential, not continuous availability. Explicitly non-production activity is excluded; existing server-side licensing events without environment are recognized, while manual tests require production/live. recentRuntimeSuccess distinguishes a licensing success from a connection test. setupVerified is historical integration evidence for the current credential, including non-production tests; it is not live health. Historical, revoked/replaced-credential, future-dated and missing records cannot claim current health. Missing history for a published product is informational, not a failure or readiness penalty. Customer-specific validation failures do not establish a platform outage.
Request, response and error reference
No request body fields are read by this operation.
HTTP 200 response (application/json)
{
"type": "object",
"properties": {
"ok": {
"type": "boolean"
},
"productId": {
"type": "string"
},
"connected": {
"type": "boolean"
},
"status": {
"type": "string"
},
"lastSeenAt": {
"type": [
"string",
"null"
],
"format": "date-time"
},
"lastSuccessAt": {
"type": [
"string",
"null"
],
"format": "date-time"
},
"pluginVersion": {
"type": [
"string",
"null"
]
},
"environment": {
"type": [
"string",
"null"
]
},
"credentialId": {
"type": [
"string",
"null"
]
},
"errorCode": {
"type": [
"string",
"null"
]
},
"errorReason": {
"type": [
"string",
"null"
]
},
"evidenceState": {
"type": "string",
"enum": [
"not_recorded",
"credential_unverified",
"recent_runtime",
"recent_test",
"historical"
]
},
"evidenceSource": {
"type": [
"string",
"null"
]
},
"setupVerified": {
"type": "boolean"
},
"recentRuntimeSuccess": {
"type": "boolean"
},
"currentCredential": {
"type": "boolean"
},
"historicalSuccess": {
"type": "boolean"
},
"recentWindowHours": {
"type": "integer"
},
"healthStatus": {
"type": "string",
"enum": [
"recent_success",
"unknown"
]
},
"message": {
"type": "string"
}
},
"additionalProperties": true
}
Documented failures: 400, 401, 403, 404, 409, 500, 503.
/api/developer/abandoned-checkout-settings
Read abandoned-checkout reminder settings
- Auth
- Account Bearer JWT
- Scope
- marketing.view and all-products scope. Product context must belong to the effective developer.
- Request fields
- query productId: integer
- Returns
- HTTP 200: settings.
- Notes
- These are developer-wide settings, not separate policies per product. Product context resolves the owning developer; delegated calls should supply an assigned productId. PUT defaults delayHours to 24 and accepts delay_hours. Saving does not send a message or bypass audience eligibility and suppression.
Request, response and error reference
Query and header parameters
[
{
"name": "productId",
"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": {
"settings": {
"type": "object",
"properties": {
"enabled": {
"type": "boolean"
},
"delayHours": {
"type": "integer",
"minimum": 1,
"maximum": 168
}
},
"additionalProperties": true
}
},
"additionalProperties": true
}
Documented failures: 400, 401, 403, 404, 409, 500, 503.
/api/developer/abandoned-checkout-settings
Save abandoned-checkout reminder settings
- Auth
- Account Bearer JWT
- Scope
- marketing.manage and all-products scope. Product context must belong to the effective developer.
- Request fields
- query productId: integer
- enabled: boolean
- delayHours: integer
- productId: integer
- Returns
- HTTP 200: settings.
- Notes
- These are developer-wide settings, not separate policies per product. Product context resolves the owning developer; delegated calls should supply an assigned productId. PUT defaults delayHours to 24 and accepts delay_hours. Saving does not send a message or bypass audience eligibility and suppression.
Request, response and error reference
Query and header parameters
[
{
"name": "productId",
"in": "query",
"schema": {
"type": "integer",
"minimum": 1
},
"required": false,
"description": ""
}
]
Request (application/json)
{
"type": "object",
"properties": {
"enabled": {
"type": "boolean"
},
"delayHours": {
"type": "integer",
"minimum": 1,
"maximum": 168
},
"productId": {
"type": "integer",
"minimum": 1
}
},
"additionalProperties": true
}
HTTP 200 response (application/json)
{
"type": "object",
"properties": {
"settings": {
"type": "object",
"properties": {
"enabled": {
"type": "boolean"
},
"delayHours": {
"type": "integer",
"minimum": 1,
"maximum": 168
}
},
"additionalProperties": true
}
},
"additionalProperties": true
}
Documented failures: 400, 401, 403, 404, 409, 500, 503.
SoundSync
Offers, grants and setup checks
Activity respects record permissions
Product identity and event type remain available to permitted analytics roles. Customer identity requires customers.view, serials require serials.view, order IDs require orders.view, and entitlement IDs require entitlements.view. Restricted fields are null. Opaque messages, actor details and nested metadata require all of these record permissions plus refunds.view, because free text can contain private refund or dispute details. The product dashboard uses the same filtering.
Connection diagnostics respect record permissions
Permission to inspect a product integration does not grant access to its customer identities or serial keys. Product connection diagnostics require credentials.view and an assigned product. Customer identity and device-linked fields additionally require customers.view; serial fields require serials.view. Restricted fields are returned as null.
Failure explanations and arbitrary nested metadata can repeat customer or serial details, so they are returned only when both record permissions are present; otherwise the explanation is null and metadata is empty. Customer-specific connection history also requires customers.view and all-products scope. Event kind, status, version, environment and timestamps remain available to permitted diagnostic users.
