Skip to content
SoundSyncAudio software platform

Guide

Serial Activation Quickstart

Implement serial activation for custom JUCE/C++ clients, including claim, email verification, claim-status resume, final activation, cache, and unlock behavior.

SoundSync

Prerequisites

Complete these before writing activation code.

PrerequisiteExact requirement
Product configuredProduct ID and activation mode exist in SoundSync.
Product credential createdYou have App ID, plugin key, plugin secret, environment, and API base URL.
Test Connection passedPOST /api/plugin-connections/verify succeeds for productId, appId, pluginKey, and pluginSecret.
Test serial availableUse a serial/license key assigned to the product and environment under test.
Machine ID strategy selectedUse a stable per-machine instance_id/machine_id. Do not regenerate on each launch.
Secure persistence selectedChoose encrypted per-product, per-environment, per-machine storage before first activation.

SoundSync

State machine

Unlock only after the final activation response.

Serial flow
1. POST /api/license/v1/claim with license_key, instance_id, email.
2. Keep claim_id and pending state locally.
3. Customer verifies by email.
4. GET /api/license/v1/claim-status with license_key, instance_id, claim_id.
5. When status is verified, read claim_activation_token.
6. POST /api/license/v1/activate with license_key, instance_id, claim_activation_token.
7. Store validation_token, activationId, productId, status, grace fields, and support fields.
8. Unlock audio/access only after final activation succeeds.

SoundSync

Request sequence

These calls work together.

POST /api/license/v1/claim

Start a serial claim when customer identity or email verification is required.

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
Product, app, credential, environment, and machine scoped.
Request fields
  • instance_id: string
  • machine_id: string
  • product_id: integer
  • plugin_version: string
  • version: string
  • license_key: string (required)
  • email: string (required)
Returns
pending_email_verification with claim_id/claimId and emailSent when verification is required.
Side effects
Creates or restores a pending serial claim and can send the verification email.
Notes
Requires a serial/license_key, customer email and instance_id (machine_id is an alias). A pending response includes claim_id and emailSent:true; it does not activate the device. 503 VERIFICATION_EMAIL_FAILED with emailSent:false is not confirmed delivery or authorization: retry the claim deliberately after recovery. Owner mismatch/login-required errors do not transfer ownership. Keep the same serial and machine through claim-status and final activation. A compatibility CUSTOMER_ACCOUNT_EXISTS response directs account login/password recovery, not offline access.
Request, response and error reference

Request (application/json)

{
  "type": "object",
  "properties": {
    "instance_id": {
      "type": "string"
    },
    "machine_id": {
      "type": "string"
    },
    "product_id": {
      "type": "integer",
      "minimum": 1
    },
    "plugin_version": {
      "type": "string"
    },
    "version": {
      "type": "string"
    },
    "license_key": {
      "type": "string"
    },
    "email": {
      "type": "string",
      "format": "email"
    }
  },
  "required": [
    "license_key",
    "email"
  ],
  "additionalProperties": true,
  "anyOf": [
    {
      "required": [
        "instance_id"
      ]
    },
    {
      "required": [
        "machine_id"
      ]
    }
  ]
}

HTTP 200 response (application/json)

{
  "type": "object",
  "properties": {
    "ok": {
      "type": "boolean"
    },
    "status": {
      "type": "string"
    },
    "code": {
      "type": "string"
    },
    "claim_id": {
      "type": "string"
    },
    "claimId": {
      "type": "string"
    },
    "emailSent": {
      "type": "boolean"
    },
    "message": {
      "type": "string"
    },
    "nextAction": {
      "type": "string"
    },
    "passwordResetUrl": {
      "type": "string"
    },
    "claimRequired": {
      "type": "boolean"
    },
    "ownerVerificationRequired": {
      "type": "boolean"
    },
    "requiredFields": {
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "claim_activation_token": {
      "type": "string"
    },
    "claimActivationToken": {
      "type": "string"
    }
  },
  "additionalProperties": true
}

Documented failures: 400, 401, 403, 429, 500, 503.

Operation errors: IDENTITY_FIELDS_REQUIRED, INVALID_EMAIL, SERIAL_OWNER_EMAIL_MISMATCH, SERIAL_OWNER_LOGIN_REQUIRED, VERIFICATION_EMAIL_FAILED.

GET /api/license/v1/claim-status

Restore a pending serial claim and receive claim activation material after email verification.

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
Product, app, credential, environment, and machine scoped.
Request fields
  • query license_key: string (required)
  • query instance_id: string (required)
  • query claim_id: string
Returns
pending_email_verification, verified with claim_activation_token/claimActivationToken, or identity_required. Inspect status/code and ok; HTTP 200 alone is not activation.
Side effects
Does not activate the machine. The client must call /activate after verified status.
Notes
HTTP 200 may mean pending_email_verification, verified or identity_required; inspect status/code and ok. Only verified returns claim_activation_token for a separate final POST /activate on the same product/serial/machine. 400 VERIFICATION_RESTART_REQUIRED means the link expired or was not sent: submit email and serial to /claim again instead of polling forever. A confirmed owner/access denial is not offline grace. Pending polling/finalization can retry transient outages without discarding the saved claim. GET is a compatibility transport; prefer POST to keep serial/proof out of URLs and logs.
Request, response and error reference

Query and header parameters

[
  {
    "name": "license_key",
    "in": "query",
    "required": true,
    "schema": {
      "type": "string"
    }
  },
  {
    "name": "instance_id",
    "in": "query",
    "required": true,
    "schema": {
      "type": "string"
    }
  },
  {
    "name": "claim_id",
    "in": "query",
    "required": false,
    "schema": {
      "type": "string"
    }
  }
]

HTTP 200 response (application/json)

{
  "type": "object",
  "properties": {
    "ok": {
      "type": "boolean"
    },
    "status": {
      "type": "string"
    },
    "code": {
      "type": "string"
    },
    "claim_id": {
      "type": "string"
    },
    "claimId": {
      "type": "string"
    },
    "emailSent": {
      "type": "boolean"
    },
    "message": {
      "type": "string"
    },
    "nextAction": {
      "type": "string"
    },
    "passwordResetUrl": {
      "type": "string"
    },
    "claimRequired": {
      "type": "boolean"
    },
    "ownerVerificationRequired": {
      "type": "boolean"
    },
    "requiredFields": {
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "claim_activation_token": {
      "type": "string"
    },
    "claimActivationToken": {
      "type": "string"
    }
  },
  "additionalProperties": true
}

Documented failures: 400, 401, 403, 429, 500, 503.

Operation errors: VERIFICATION_RESTART_REQUIRED.

POST /api/license/v1/claim-status

Restore a pending serial claim and receive claim activation material after email verification.

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
Product, app, credential, environment, and machine scoped.
Request fields
  • instance_id: string (required)
  • machine_id: string
  • product_id: integer
  • plugin_version: string
  • version: string
  • license_key: string (required)
  • claim_id: string
Returns
pending_email_verification, verified with claim_activation_token/claimActivationToken, or identity_required. Inspect status/code and ok; HTTP 200 alone is not activation.
Side effects
Does not activate the machine. The client must call /activate after verified status.
Notes
HTTP 200 may mean pending_email_verification, verified or identity_required; inspect status/code and ok. Only verified returns claim_activation_token for a separate final POST /activate on the same product/serial/machine. 400 VERIFICATION_RESTART_REQUIRED means the link expired or was not sent: submit email and serial to /claim again instead of polling forever. A confirmed owner/access denial is not offline grace. Pending polling/finalization can retry transient outages without discarding the saved claim. GET is a compatibility transport; prefer POST to keep serial/proof out of URLs and logs.
Request, response and error reference

Request (application/json)

{
  "type": "object",
  "properties": {
    "instance_id": {
      "type": "string"
    },
    "machine_id": {
      "type": "string"
    },
    "product_id": {
      "type": "integer",
      "minimum": 1
    },
    "plugin_version": {
      "type": "string"
    },
    "version": {
      "type": "string"
    },
    "license_key": {
      "type": "string"
    },
    "claim_id": {
      "type": "string"
    }
  },
  "required": [
    "license_key",
    "instance_id"
  ],
  "additionalProperties": true
}

HTTP 200 response (application/json)

{
  "type": "object",
  "properties": {
    "ok": {
      "type": "boolean"
    },
    "status": {
      "type": "string"
    },
    "code": {
      "type": "string"
    },
    "claim_id": {
      "type": "string"
    },
    "claimId": {
      "type": "string"
    },
    "emailSent": {
      "type": "boolean"
    },
    "message": {
      "type": "string"
    },
    "nextAction": {
      "type": "string"
    },
    "passwordResetUrl": {
      "type": "string"
    },
    "claimRequired": {
      "type": "boolean"
    },
    "ownerVerificationRequired": {
      "type": "boolean"
    },
    "requiredFields": {
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "claim_activation_token": {
      "type": "string"
    },
    "claimActivationToken": {
      "type": "string"
    }
  },
  "additionalProperties": true
}

Documented failures: 400, 401, 403, 429, 500, 503.

Operation errors: VERIFICATION_RESTART_REQUIRED.

POST /api/license/v1/activate

Activate the current machine after direct serial/customer proof or a verified serial claim.

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
Product, app, credential, environment, and machine scoped.
Request fields
  • instance_id: string
  • machine_id: string
  • product_id: integer
  • plugin_version: string
  • version: string
  • license_key: string
  • serial: string
  • email: string
  • validation_token: string
  • token: string
  • activationId: value
  • licenseReference: string
  • plugin_session_id: string
  • device_credential: string. Private renewal proof returned by authorized enrollment; deviceCredential is an accepted body alias. Bind to the same app/product and instance_id. It cannot independently unlock offline audio.
  • license_kind: serial | email_entitlement
  • device_credential_supported: boolean. Send true to request native renewal-credential enrollment. deviceCredentialSupported is an accepted body alias.
  • claim_id: string
  • claim_activation_token: string
Returns
status activated, activationId, validation_token, entitlement_id, customer, max_activations, remaining, productId, grace_expires_at, offline_grace_days.
Side effects
Creates or reactivates a machine activation, ensures entitlement state, marks serial redeemed/billing eligible where applicable, records events, and issues a validation token.
Notes
Generated native clients request device_credential_supported:true and retain the returned device_credential, plugin_session_id and newest validation_token privately. Device proof can renew after a short-lived token/session expires, but never bypasses revoked access, product/device binding or entitlement checks. device_credential_status:pending is incomplete enrollment, not an offline grant. Only an authorized signed offline_lease can support JUCE offline access.
Request, response and error reference

Request (application/json)

{
  "type": "object",
  "properties": {
    "instance_id": {
      "type": "string"
    },
    "machine_id": {
      "type": "string"
    },
    "product_id": {
      "type": "integer",
      "minimum": 1
    },
    "plugin_version": {
      "type": "string"
    },
    "version": {
      "type": "string"
    },
    "license_key": {
      "type": "string"
    },
    "serial": {
      "type": "string"
    },
    "email": {
      "type": "string",
      "format": "email"
    },
    "validation_token": {
      "type": "string"
    },
    "token": {
      "type": "string"
    },
    "activationId": {
      "oneOf": [
        {
          "type": "integer",
          "minimum": 1
        },
        {
          "type": "string",
          "pattern": "^[1-9][0-9]*$"
        }
      ]
    },
    "licenseReference": {
      "type": "string"
    },
    "plugin_session_id": {
      "type": "string"
    },
    "device_credential": {
      "type": "string",
      "description": "Private renewal proof returned by authorized enrollment; deviceCredential is an accepted body alias. Bind to the same app/product and instance_id. It cannot independently unlock offline audio."
    },
    "license_kind": {
      "type": "string",
      "enum": [
        "serial",
        "email_entitlement"
      ]
    },
    "device_credential_supported": {
      "type": "boolean",
      "description": "Send true to request native renewal-credential enrollment. deviceCredentialSupported is an accepted body alias."
    },
    "claim_id": {
      "type": "string"
    },
    "claim_activation_token": {
      "type": "string"
    }
  },
  "additionalProperties": true,
  "anyOf": [
    {
      "required": [
        "instance_id"
      ]
    },
    {
      "required": [
        "machine_id"
      ]
    }
  ]
}

HTTP 200 response (application/json)

{
  "type": "object",
  "properties": {
    "ok": {
      "type": "boolean"
    },
    "status": {
      "type": "string"
    },
    "code": {
      "type": "string"
    },
    "message": {
      "type": "string"
    },
    "activationId": {
      "type": "integer",
      "minimum": 1
    },
    "validation_token": {
      "type": "string"
    },
    "entitlement_id": {
      "type": "integer",
      "minimum": 1
    },
    "customer": {
      "type": "object",
      "properties": {},
      "additionalProperties": true
    },
    "productId": {
      "type": "integer",
      "minimum": 1
    },
    "device_credential": {
      "type": "string",
      "description": "Private product/device-bound renewal proof. Returned when device_credential_supported is true and enrollment succeeds. Protect it in native secure storage; it is not a portal/library token or an offline grant."
    },
    "device_credential_status": {
      "type": "string",
      "enum": [
        "ready",
        "pending"
      ],
      "description": "pending means renewal enrollment is incomplete, even when activation was otherwise authorized. Follow the maintained client retry and access decision; do not manufacture offline authorization."
    },
    "plugin_session_id": {
      "type": "string",
      "description": "Private short-lived plugin license session. Distinct from durable device_credential and customer library tokens."
    },
    "plugin_session_expires_at": {
      "type": "string",
      "format": "date-time",
      "description": "Expiry of plugin_session_id, not the offline grace deadline."
    },
    "max_activations": {
      "type": "integer",
      "minimum": 0
    },
    "remaining": {
      "type": "integer",
      "minimum": 0
    },
    "grace_expires_at": {
      "type": [
        "string",
        "null"
      ]
    },
    "offline_grace_days": {
      "type": "integer",
      "minimum": 0
    },
    "offline_grace": {
      "type": "object",
      "properties": {
        "enabled": {
          "type": "boolean"
        },
        "days": {
          "type": "integer",
          "minimum": 0
        },
        "expiresAt": {
          "type": [
            "string",
            "null"
          ]
        }
      },
      "additionalProperties": true
    },
    "offline_lease": {
      "type": "string",
      "description": "Optional signed JSON envelope issued only by successful authorized activation/validation with a positive grace period and configured signer. Contains alg, kid, base64 payload and signature. Verify with trusted package public keys; decoding alone is not authorization. Never log customer grants."
    }
  },
  "additionalProperties": true
}

Documented failures: 400, 401, 403, 500, 503.

SoundSync

Important answers

These are the behaviors custom clients most often get wrong.

QuestionAnswer
Does /claim activate the machine?No. It creates/restores a pending claim and may send verification email.
Does email verification activate the machine?No. It verifies the claim so the plugin can restore claim status.
Does /claim-status activate the machine?No. A verified claim-status returns claim_activation_token.
What is passed to /activate?license_key, instance_id, claim_activation_token, and optionally claim_id plus version/product context.
What survives restart?Pending claim fields such as license_key, instance_id, claim_id, email, productId, environment, and started-at timestamp; do not store customer password.
How often may polling run?HISE runtime observes 2-second polling up to 120 attempts. Custom clients should not poll faster than that.
What if the claim expires?Claim verification tokens are 48-hour email tokens; claim activation material is short-lived. Restart claim if eligible.

Package-specific access policy

JUCE 0.7.3 supports signed offline access for the grace period selected in product Access settings, through 90 days. A prior successful activation or validation and the matching package verification keys are required. Startup uses a verified unexpired grant or online authorization. Zero, disabled, missing or expired grace requires online authorization; confirmed denial or deactivation locks access. Regenerate and rebuild older plugins to use this release.