API reference
Customer and Serial Management API
Current developer customer tables, serial inventory, imports, purchase history and manual access grants.
Use the current developer-scoped serial routes
For new integrations, use /api/developer/serials rather than the deprecated /api/serials table handlers. Account identity, workspace permissions and assigned products determine access. Supplying another developer ID or broadening a filter does not grant their records.
Lists use page, limit, search, dateRange and supported product filters. Serial inventory distinguishes available and redeemed. Purchases additionally accept channel, productIds, resellerId, provider, refundStatus, recordType, dateFrom and dateTo. IDs in historical or external purchase rows are not automatically refundable managed-checkout order IDs.
Generate and import deliberately
Serial generation requires an owned product and current billing eligibility. Prefix and expiry are inventory settings, not proof of a customer purchase. Reseller serial pools belong in Partners > Licenses; ordinary developer generation rejects reseller assignment.
Download the current CSV template before importing. Upload file as multipart data or send the named customers, serials or purchases JSON array. Product mappings must resolve to allowed products. A 207 result contains row errors and successful rows; correct the failures rather than replaying every row. Purchase imports do not collect payment, transfer billing authority or send purchase marketing messages.
SoundSync
Illustrative owned-product serial generation
curl --fail-with-body -sS -X POST "$SOUNDSYNC_API_BASE/api/developer/serials/generate" \
-H "Authorization: Bearer $DEVELOPER_TOKEN" \
-H "Content-Type: application/json" \
--data '{"productId":123,"quantity":5,"prefix":"DEMO"}'
Access, history and payment are separate
Activate, reactivate, deactivate, suspend, unsuspend and revoke are administrative serial actions. Hiding an order only changes its supported history presentation. Neither action refunds a payment.
Manual grants give the selected customer access to explicit products. Existing-serial assignment and subscription access grants have single-product restrictions. An access grant does not authorize billing; use the separate supported customer-confirmed payment setup when needed. Keep the reason and grant request reference for reconciliation.
Read access-only history without inventing a payment
GET /api/developer/purchases groups related items under purchase_key. An access-only row uses order_type:access_grant, financial_record:false, invoice_available:false and null order_id/order_item_id. Its access_entitlement_id identifies access, not a paid order. display_order_id falls back to a reference such as ACCESS-123. For a product earned from a subscription, it can instead display the original funding order, also returned as original_subscription_order_id. That display-only link does not make this access row refundable or give it an invoice.
Use recordType:access to select these rows; recordType:order and pool select the other supported record kinds. channel:subscription includes subscription history. These filters do not change ownership or expand product permissions. A subscription payment and a product earned from it are distinct history entries, not two charges. Earned subscription products show zero-cost item totals in the funding order currency; their CSV subtotal and final item total are 0, while the financial order total stays blank. Other non-financial access rows leave financial totals blank. Never add access-only rows to sales revenue or treat their display reference as refund authority.
A manual history entry can retain existing access
A standard product grant can record a manual grant even when the customer already has active access. historyRecorded and alreadyHadAccess describe this result; metadata.manualGrantExistingAccess identifies the retained-access history. It preserves the original entitlement, serial and provenance, without another payment, settlement credit or repeated marketing enrollment.
For that history-only order item, remove-access without deleteRecord:true returns 409 MANUAL_GRANT_HISTORY_ONLY. With deleteRecord:true, it hides the manual history and returns recordOnly:true with zero revocations; the original access remains. Manage the original entitlement or serial separately when an authorized access change is intended. Reuse grantRequestId for the same request after an uncertain response, not for a different grant.
Customer removal is not global account deletion
Removal requires customers.manage and confirm:true or confirmation:"yes". It removes the developer customer relationship and supported associated marketing records. Required purchases, financial history and global account identity are separate. Use the verified privacy-request procedure for broader deletion requests.
Protect the customer login
Workspace-wide contact edits, deletion, customer imports and verification resends require all-products scope and customers.manage. Product-scoped staff can continue using permitted serial and purchase controls; a customer ID cannot expand those permissions.
A developer edit cannot change a linked login email or replace a password. Direct the customer to account settings to verify an email change, or to Reset password for recovery. A contact-only email correction is permitted only when no login is linked and no other developer shares the identity; it clears email verification. Supported name and phone corrections can update a shared customer profile, not just one storefront label.
Read the result of recovery actions
Internal notes are private support records. Activity and plugin-connection reports can contain customer identity and serial diagnostics; never publish them unredacted. Activation reset clears the supported machines and sessions without refunding or granting products.
An access-email action returns an email outcome object plus libraryUrl. HTTP 200 alone does not mean the provider accepted a message: inspect sent, skipped, reason or error. Required sender configuration and the current stored customer identity still apply.
SoundSync
Related customer operations
SoundSync
Requests and responses
/api/developer/customers
Search developer-scoped customers
- Auth
- Account Bearer JWT
- Scope
- Authenticated account, effective developer workspace, applicable permissions and product ownership. Read the operation notes for legacy or owner-only restrictions.
- Request fields
- query page: integer
- query limit: integer
- query search: string
- query dateRange: string
- query productId: integer
- Returns
- HTTP 200: rows, total, page, pageSize.
- Notes
- Account permissions and assigned products determine scope; query filters cannot expand it. Purchase identifiers can include external/manual references; they are not all eligible managed-payment refund IDs.
Request, response and error reference
Query and header parameters
[
{
"name": "page",
"in": "query",
"schema": {
"type": "integer",
"minimum": 1
},
"required": false,
"description": ""
},
{
"name": "limit",
"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": ""
},
{
"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": {
"rows": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": [
"integer",
"string"
],
"minLength": 1
},
"customer_id": {
"type": "integer",
"minimum": 1
},
"email": {
"type": "string",
"format": "email"
},
"first_name": {
"type": [
"string",
"null"
]
},
"last_name": {
"type": [
"string",
"null"
]
},
"status": {
"type": "string"
},
"email_verification_status": {
"type": "string"
}
},
"additionalProperties": true
}
},
"total": {
"type": "integer"
},
"page": {
"type": "integer"
},
"pageSize": {
"type": "integer"
}
},
"additionalProperties": true
}
Documented failures: 400, 401, 403, 404, 409, 500, 503.
/api/developer/customers/export
Export authorized customers as CSV
- Auth
- Account Bearer JWT
- Scope
- Authenticated account, effective developer workspace, applicable permissions and product ownership. Read the operation notes for legacy or owner-only restrictions.
- Request fields
- query page: integer
- query limit: integer
- query search: string
- query dateRange: string
- query productId: integer
- Returns
- HTTP 200: text/csv.
Request, response and error reference
Query and header parameters
[
{
"name": "page",
"in": "query",
"schema": {
"type": "integer",
"minimum": 1
},
"required": false,
"description": ""
},
{
"name": "limit",
"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": ""
},
{
"name": "productId",
"in": "query",
"schema": {
"type": "integer",
"minimum": 1
},
"required": false,
"description": ""
}
]
No request body fields are read by this operation.
HTTP 200 response (text/csv)
{
"type": "string",
"format": "binary"
}
Documented failures: 400, 401, 403, 404, 409, 500, 503.
/api/developer/customers/demo-csv
Download the customers import template
- Auth
- Account Bearer JWT
- Scope
- Authenticated account, effective developer workspace, applicable permissions and product ownership. Read the operation notes for legacy or owner-only restrictions.
- Returns
- HTTP 200: text/csv.
Request, response and error reference
No request body fields are read by this operation.
HTTP 200 response (text/csv)
{
"type": "string",
"format": "binary"
}
Documented failures: 400, 401, 403, 404, 409, 500, 503.
/api/developer/customers/import
Import reviewed customers rows
- Auth
- Account Bearer JWT
- Scope
- Authenticated account, effective developer workspace, applicable permissions and product ownership. Read the operation notes for legacy or owner-only restrictions.
- Request fields
- file: string
- customers: array
- productMappings: object. Operation-specific extension data; do not put credentials or unnecessary personal information here.
- Returns
- HTTP 201: success, importedCount, insertedCount, errors.
- Notes
- Send a CSV file under file or the named JSON row array. Inspect row errors on 207; do not blindly replay already imported rows. Product mappings do not bypass ownership. Customer imports require customers.manage and all-products scope; purchase imports require entitlements.manage and serial imports require serials.manage, with assigned-product checks. Purchase import does not collect payment or transfer provider billing authority and disables purchase marketing/email activity.
Request, response and error reference
Request (application/json or multipart/form-data)
{
"type": "object",
"properties": {
"file": {
"type": "string",
"format": "binary"
},
"customers": {
"type": "array",
"items": {
"type": "object",
"properties": {
"email": {
"type": "string",
"format": "email"
},
"firstName": {
"type": "string"
},
"lastName": {
"type": "string"
},
"productId": {
"type": "integer",
"minimum": 1
},
"productName": {
"type": "string"
},
"serialCode": {
"type": "string"
},
"price": {
"type": "number"
},
"salePrice": {
"type": "number"
},
"date": {
"type": "string"
}
},
"additionalProperties": true
}
},
"productMappings": {
"type": "object",
"additionalProperties": true,
"description": "Operation-specific extension data; do not put credentials or unnecessary personal information here."
}
},
"additionalProperties": true
}
HTTP 201 response (application/json)
{
"type": "object",
"properties": {
"success": {
"type": "boolean"
},
"importedCount": {
"type": "integer"
},
"insertedCount": {
"type": "integer"
},
"errors": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": true,
"description": "Operation-specific extension data; do not put credentials or unnecessary personal information here."
}
}
},
"additionalProperties": true
}
Documented failures: 400, 401, 403, 404, 409, 500, 503.
/api/developer/serials
Search serial inventory and device counts
- Auth
- Account Bearer JWT
- Scope
- Authenticated account, effective developer workspace, applicable permissions and product ownership. Read the operation notes for legacy or owner-only restrictions.
- Request fields
- query page: integer
- query limit: integer
- query search: string
- query dateRange: string
- query productId: integer
- query status: string
- Returns
- HTTP 200: rows, total, page, pageSize.
- Notes
- Account permissions and assigned products determine scope; query filters cannot expand it. Purchase identifiers can include external/manual references; they are not all eligible managed-payment refund IDs.
Request, response and error reference
Query and header parameters
[
{
"name": "page",
"in": "query",
"schema": {
"type": "integer",
"minimum": 1
},
"required": false,
"description": ""
},
{
"name": "limit",
"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": ""
},
{
"name": "productId",
"in": "query",
"schema": {
"type": "integer",
"minimum": 1
},
"required": false,
"description": ""
},
{
"name": "status",
"in": "query",
"schema": {
"type": "string",
"enum": [
"available",
"redeemed"
]
},
"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",
"string"
],
"minLength": 1
},
"serial": {
"type": "string"
},
"product_id": {
"type": "integer",
"minimum": 1
},
"product": {
"type": "string"
},
"customer_id": {
"type": [
"integer",
"null"
]
},
"status": {
"type": "string"
},
"redeemed": {
"type": "boolean"
},
"revoked": {
"type": "boolean"
},
"active_activation_count": {
"type": "integer"
},
"max_activations": {
"type": "integer"
},
"remaining_activations": {
"type": "integer"
}
},
"additionalProperties": true
}
},
"total": {
"type": "integer"
},
"page": {
"type": "integer"
},
"pageSize": {
"type": "integer"
}
},
"additionalProperties": true
}
Documented failures: 400, 401, 403, 404, 409, 500, 503.
/api/developer/serials/export
Export authorized serials as CSV
- Auth
- Account Bearer JWT
- Scope
- Authenticated account, effective developer workspace, applicable permissions and product ownership. Read the operation notes for legacy or owner-only restrictions.
- Request fields
- query page: integer
- query limit: integer
- query search: string
- query dateRange: string
- query productId: integer
- Returns
- HTTP 200: text/csv.
Request, response and error reference
Query and header parameters
[
{
"name": "page",
"in": "query",
"schema": {
"type": "integer",
"minimum": 1
},
"required": false,
"description": ""
},
{
"name": "limit",
"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": ""
},
{
"name": "productId",
"in": "query",
"schema": {
"type": "integer",
"minimum": 1
},
"required": false,
"description": ""
}
]
No request body fields are read by this operation.
HTTP 200 response (text/csv)
{
"type": "string",
"format": "binary"
}
Documented failures: 400, 401, 403, 404, 409, 500, 503.
/api/developer/serials/demo-csv
Download the serials import template
- Auth
- Account Bearer JWT
- Scope
- Authenticated account, effective developer workspace, applicable permissions and product ownership. Read the operation notes for legacy or owner-only restrictions.
- Returns
- HTTP 200: text/csv.
Request, response and error reference
No request body fields are read by this operation.
HTTP 200 response (text/csv)
{
"type": "string",
"format": "binary"
}
Documented failures: 400, 401, 403, 404, 409, 500, 503.
/api/developer/serials/import
Import reviewed serials rows
- Auth
- Account Bearer JWT
- Scope
- Authenticated account, effective developer workspace, applicable permissions and product ownership. Read the operation notes for legacy or owner-only restrictions.
- Request fields
- file: string
- serials: array
- productMappings: object. Operation-specific extension data; do not put credentials or unnecessary personal information here.
- Returns
- HTTP 201: success, importedCount, insertedCount, errors.
- Notes
- Send a CSV file under file or the named JSON row array. Inspect row errors on 207; do not blindly replay already imported rows. Product mappings do not bypass ownership. Customer imports require customers.manage and all-products scope; purchase imports require entitlements.manage and serial imports require serials.manage, with assigned-product checks. Purchase import does not collect payment or transfer provider billing authority and disables purchase marketing/email activity.
Request, response and error reference
Request (application/json or multipart/form-data)
{
"type": "object",
"properties": {
"file": {
"type": "string",
"format": "binary"
},
"serials": {
"type": "array",
"items": {
"type": "object",
"properties": {
"email": {
"type": "string",
"format": "email"
},
"firstName": {
"type": "string"
},
"lastName": {
"type": "string"
},
"productId": {
"type": "integer",
"minimum": 1
},
"productName": {
"type": "string"
},
"serialCode": {
"type": "string"
},
"price": {
"type": "number"
},
"salePrice": {
"type": "number"
},
"date": {
"type": "string"
}
},
"additionalProperties": true
}
},
"productMappings": {
"type": "object",
"additionalProperties": true,
"description": "Operation-specific extension data; do not put credentials or unnecessary personal information here."
}
},
"additionalProperties": true
}
HTTP 201 response (application/json)
{
"type": "object",
"properties": {
"success": {
"type": "boolean"
},
"importedCount": {
"type": "integer"
},
"insertedCount": {
"type": "integer"
},
"errors": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": true,
"description": "Operation-specific extension data; do not put credentials or unnecessary personal information here."
}
}
},
"additionalProperties": true
}
Documented failures: 400, 401, 403, 404, 409, 500, 503.
/api/developer/purchases
Search grouped purchase and access history
- Auth
- Account Bearer JWT
- Scope
- Authenticated account, effective developer workspace, applicable permissions and product ownership. Read the operation notes for legacy or owner-only restrictions.
- Request fields
- query page: integer
- query limit: integer
- query search: string
- query dateRange: string
- query productId: integer
- query channel: value
- query productIds: string
- query resellerId: string
- query provider: value
- query refundStatus: value
- query recordType: value
- query dateFrom: string
- query dateTo: string
- Returns
- HTTP 200: rows, total, page, pageSize, canRefund.
- Notes
- Account permissions and assigned products determine scope; query filters cannot expand it. Purchase rows group items by purchase_key. Access-only rows have order_type:access_grant, financial_record:false, invoice_available:false and null order_id/order_item_id. display_order_id falls back to ACCESS-<entitlement ID>; an earned subscription product can instead display the funding order, with original_subscription_order_id as a separate reference and zero-cost item totals. Neither display value makes the access row a payment, invoice or refundable order. channel:subscription includes subscription history; recordType:access selects access-only rows. canRefund is a caller capability, not per-row eligibility. Purchase identifiers can also include external/manual references; use the refund preview for an eligible managed-payment order.
Request, response and error reference
Query and header parameters
[
{
"name": "page",
"in": "query",
"schema": {
"type": "integer",
"minimum": 1
},
"required": false,
"description": ""
},
{
"name": "limit",
"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": ""
},
{
"name": "productId",
"in": "query",
"schema": {
"type": "integer",
"minimum": 1
},
"required": false,
"description": ""
},
{
"name": "channel",
"in": "query",
"schema": {
"enum": [
"all",
"direct",
"marketplace",
"reseller",
"manual",
"import",
"free",
"subscription",
"other"
]
},
"required": false,
"description": ""
},
{
"name": "productIds",
"in": "query",
"schema": {
"type": "string"
},
"required": false,
"description": ""
},
{
"name": "resellerId",
"in": "query",
"schema": {
"type": "string"
},
"required": false,
"description": ""
},
{
"name": "provider",
"in": "query",
"schema": {
"enum": [
"all",
"stripe",
"paypal",
"other",
"unknown"
]
},
"required": false,
"description": ""
},
{
"name": "refundStatus",
"in": "query",
"schema": {
"enum": [
"all",
"none",
"partial",
"full",
"unknown"
]
},
"required": false,
"description": ""
},
{
"name": "recordType",
"in": "query",
"schema": {
"enum": [
"all",
"order",
"pool",
"access"
]
},
"required": false,
"description": ""
},
{
"name": "dateFrom",
"in": "query",
"schema": {
"type": "string"
},
"required": false,
"description": ""
},
{
"name": "dateTo",
"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": {
"order_id": {
"type": [
"integer",
"string",
"null"
],
"minLength": 1
},
"order_item_id": {
"type": [
"integer",
"string",
"null"
],
"minLength": 1
},
"product_id": {
"type": "integer",
"minimum": 1
},
"product": {
"type": "string"
},
"customer_id": {
"type": "integer",
"minimum": 1
},
"status": {
"type": "string"
},
"invoice_available": {
"type": "boolean"
},
"financial_record": {
"type": "boolean"
},
"order_type": {
"type": "string"
},
"purchase_channel": {
"type": "string"
},
"access_entitlement_id": {
"type": [
"integer",
"string"
],
"minLength": 1
},
"entitlement_id": {
"type": [
"integer",
"string",
"null"
],
"minLength": 1
},
"entitlement_state": {
"type": [
"string",
"null"
]
},
"display_order_id": {
"type": "string"
},
"original_subscription_order_id": {
"type": [
"integer",
"string",
"null"
],
"minLength": 1
},
"currency": {
"type": "string"
},
"item_subtotal_cents": {
"type": "integer"
},
"final_total_cents": {
"type": "integer"
},
"total_cents": {
"type": "integer"
},
"purchase_key": {
"type": "string"
},
"occurred_at": {
"type": [
"string",
"null"
],
"format": "date-time"
},
"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."
},
"items": {
"type": "array",
"items": {
"type": "object",
"properties": {
"order_id": {
"type": [
"integer",
"string",
"null"
],
"minLength": 1
},
"order_item_id": {
"type": [
"integer",
"string",
"null"
],
"minLength": 1
},
"product_id": {
"type": "integer",
"minimum": 1
},
"product": {
"type": "string"
},
"customer_id": {
"type": "integer",
"minimum": 1
},
"status": {
"type": "string"
},
"invoice_available": {
"type": "boolean"
},
"financial_record": {
"type": "boolean"
},
"order_type": {
"type": "string"
},
"purchase_channel": {
"type": "string"
},
"access_entitlement_id": {
"type": [
"integer",
"string"
],
"minLength": 1
},
"entitlement_id": {
"type": [
"integer",
"string",
"null"
],
"minLength": 1
},
"entitlement_state": {
"type": [
"string",
"null"
]
},
"display_order_id": {
"type": "string"
},
"original_subscription_order_id": {
"type": [
"integer",
"string",
"null"
],
"minLength": 1
},
"currency": {
"type": "string"
},
"item_subtotal_cents": {
"type": "integer"
},
"final_total_cents": {
"type": "integer"
},
"total_cents": {
"type": "integer"
},
"purchase_key": {
"type": "string"
},
"occurred_at": {
"type": [
"string",
"null"
],
"format": "date-time"
},
"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
}
},
"total": {
"type": "integer"
},
"page": {
"type": "integer"
},
"pageSize": {
"type": "integer"
},
"canRefund": {
"type": "boolean"
}
},
"additionalProperties": true
}
Documented failures: 400, 401, 403, 404, 409, 500, 503.
/api/developer/purchases/export
Export authorized purchases as CSV
- Auth
- Account Bearer JWT
- Scope
- Authenticated account, effective developer workspace, applicable permissions and product ownership. Read the operation notes for legacy or owner-only restrictions.
- Request fields
- query page: integer
- query limit: integer
- query search: string
- query dateRange: string
- query productId: integer
- Returns
- HTTP 200: text/csv.
Request, response and error reference
Query and header parameters
[
{
"name": "page",
"in": "query",
"schema": {
"type": "integer",
"minimum": 1
},
"required": false,
"description": ""
},
{
"name": "limit",
"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": ""
},
{
"name": "productId",
"in": "query",
"schema": {
"type": "integer",
"minimum": 1
},
"required": false,
"description": ""
}
]
No request body fields are read by this operation.
HTTP 200 response (text/csv)
{
"type": "string",
"format": "binary"
}
Documented failures: 400, 401, 403, 404, 409, 500, 503.
/api/developer/purchases/demo-csv
Download the purchases import template
- Auth
- Account Bearer JWT
- Scope
- Authenticated account, effective developer workspace, applicable permissions and product ownership. Read the operation notes for legacy or owner-only restrictions.
- Returns
- HTTP 200: text/csv.
Request, response and error reference
No request body fields are read by this operation.
HTTP 200 response (text/csv)
{
"type": "string",
"format": "binary"
}
Documented failures: 400, 401, 403, 404, 409, 500, 503.
/api/developer/purchases/import
Import reviewed purchases rows
- Auth
- Account Bearer JWT
- Scope
- Authenticated account, effective developer workspace, applicable permissions and product ownership. Read the operation notes for legacy or owner-only restrictions.
- Request fields
- file: string
- purchases: array
- productMappings: object. Operation-specific extension data; do not put credentials or unnecessary personal information here.
- Returns
- HTTP 201: success, importedCount, insertedCount, errors.
- Notes
- Send a CSV file under file or the named JSON row array. Inspect row errors on 207; do not blindly replay already imported rows. Product mappings do not bypass ownership. Customer imports require customers.manage and all-products scope; purchase imports require entitlements.manage and serial imports require serials.manage, with assigned-product checks. Purchase import does not collect payment or transfer provider billing authority and disables purchase marketing/email activity.
Request, response and error reference
Request (application/json or multipart/form-data)
{
"type": "object",
"properties": {
"file": {
"type": "string",
"format": "binary"
},
"purchases": {
"type": "array",
"items": {
"type": "object",
"properties": {
"email": {
"type": "string",
"format": "email"
},
"firstName": {
"type": "string"
},
"lastName": {
"type": "string"
},
"productId": {
"type": "integer",
"minimum": 1
},
"productName": {
"type": "string"
},
"serialCode": {
"type": "string"
},
"price": {
"type": "number"
},
"salePrice": {
"type": "number"
},
"date": {
"type": "string"
}
},
"additionalProperties": true
}
},
"productMappings": {
"type": "object",
"additionalProperties": true,
"description": "Operation-specific extension data; do not put credentials or unnecessary personal information here."
}
},
"additionalProperties": true
}
HTTP 201 response (application/json)
{
"type": "object",
"properties": {
"success": {
"type": "boolean"
},
"importedCount": {
"type": "integer"
},
"insertedCount": {
"type": "integer"
},
"errors": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": true,
"description": "Operation-specific extension data; do not put credentials or unnecessary personal information here."
}
}
},
"additionalProperties": true
}
Documented failures: 400, 401, 403, 404, 409, 500, 503.
/api/developer/customers/{customerId}
Remove supported developer customer information
- Auth
- Account Bearer JWT
- Scope
- The developer customer relationship and all-products workspace scope. Mutations require the operation-specific manage permission; a linked login credential is never changed by a contact edit.
- Request fields
- confirm: boolean
- confirmation: string
- reason: string
- Returns
- HTTP 200: ok, alreadyRemoved, already_removed, customer_id, developer_customer_id, message.
- Notes
- Requires customers.manage, all-products workspace scope and confirm:true or confirmation:"yes". This removes the developer contact relationship and supported marketing records, not the global account, purchases or required financial records. Review the account-closure and privacy-request guides.
Request, response and error reference
Request (application/json)
{
"type": "object",
"properties": {
"confirm": {
"type": "boolean"
},
"confirmation": {
"type": "string"
},
"reason": {
"type": "string"
}
},
"additionalProperties": true,
"anyOf": [
{
"properties": {
"confirm": {
"const": true
}
},
"required": [
"confirm"
]
},
{
"properties": {
"confirmation": {
"type": "string",
"pattern": "^\\s*[Yy][Ee][Ss]\\s*$"
}
},
"required": [
"confirmation"
]
}
]
}
HTTP 200 response (application/json)
{
"type": "object",
"properties": {
"ok": {
"type": "boolean"
},
"alreadyRemoved": {
"type": "boolean"
},
"already_removed": {
"type": "boolean"
},
"customer_id": {
"type": "integer",
"minimum": 1
},
"developer_customer_id": {
"type": [
"integer",
"string",
"null"
]
},
"message": {
"type": "string"
}
},
"additionalProperties": true
}
Documented failures: 400, 401, 403, 404, 409, 500, 503.
/api/developer/serials/available-by-product
Group available serials by product and promotion
- Auth
- Account Bearer JWT
- Scope
- Authenticated account, effective developer workspace, applicable permissions and product ownership. Read the operation notes for legacy or owner-only restrictions.
- Request fields
- query page: integer
- query limit: integer
- query search: string
- query dateRange: string
- query productId: integer
- Returns
- HTTP 200: products, promos, rows, total, page, pageSize.
Request, response and error reference
Query and header parameters
[
{
"name": "page",
"in": "query",
"schema": {
"type": "integer",
"minimum": 1
},
"required": false,
"description": ""
},
{
"name": "limit",
"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": ""
},
{
"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": {
"products": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": true,
"description": "Operation-specific extension data; do not put credentials or unnecessary personal information here."
}
},
"promos": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": true,
"description": "Operation-specific extension data; do not put credentials or unnecessary personal information here."
}
},
"rows": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": [
"integer",
"string"
],
"minLength": 1
},
"serial": {
"type": "string"
},
"product_id": {
"type": "integer",
"minimum": 1
},
"product": {
"type": "string"
},
"customer_id": {
"type": [
"integer",
"null"
]
},
"status": {
"type": "string"
},
"redeemed": {
"type": "boolean"
},
"revoked": {
"type": "boolean"
},
"active_activation_count": {
"type": "integer"
},
"max_activations": {
"type": "integer"
},
"remaining_activations": {
"type": "integer"
}
},
"additionalProperties": true
}
},
"total": {
"type": "integer"
},
"page": {
"type": "integer"
},
"pageSize": {
"type": "integer"
}
},
"additionalProperties": true
}
Documented failures: 400, 401, 403, 404, 409, 500, 503.
/api/developer/serials/resellers
List eligible relationship and legacy reseller references
- Auth
- Account Bearer JWT
- Scope
- Authenticated account, effective developer workspace, applicable permissions and product ownership. Read the operation notes for legacy or owner-only restrictions.
- Returns
- HTTP 200: resellers.
Request, response and error reference
No request body fields are read by this operation.
HTTP 200 response (application/json)
{
"type": "object",
"properties": {
"resellers": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": [
"integer",
"string"
],
"minLength": 1
},
"name": {
"type": "string"
},
"kind": {
"type": "string"
},
"relationship_id": {
"type": "integer",
"minimum": 1
},
"developer_share_bps": {
"type": [
"integer",
"null"
]
}
},
"additionalProperties": true
}
}
},
"additionalProperties": true
}
Documented failures: 400, 401, 403, 404, 409, 500, 503.
/api/developer/serials/generate
Generate unique serials for an owned product
- Auth
- Account Bearer JWT
- Scope
- Authenticated account, effective developer workspace, applicable permissions and product ownership. Read the operation notes for legacy or owner-only restrictions.
- Request fields
- productId: integer
- product_id: integer
- quantity: integer (required)
- prefix: string
- expiresAt: string,null
- promoPrice: number
- promoStart: string,null
- promoExpires: string,null
- activeFrom: string,null
- activeTo: string,null
- batchTag: string
- notes: string
- Returns
- HTTP 201: message, count, product, serials.
- Notes
- product_id and corresponding snake_case date/price aliases remain accepted. Use Partners > Licenses for reseller serial pools; reseller assignment on this route returns PARTNER_POOL_REQUIRED. Existing billing and product-scope checks apply.
Request, response and error reference
Request (application/json)
{
"type": "object",
"properties": {
"productId": {
"type": "integer",
"minimum": 1
},
"product_id": {
"type": "integer",
"minimum": 1
},
"quantity": {
"type": "integer",
"minimum": 1,
"maximum": 1000
},
"prefix": {
"type": "string"
},
"expiresAt": {
"type": [
"string",
"null"
],
"format": "date-time"
},
"promoPrice": {
"type": "number"
},
"promoStart": {
"type": [
"string",
"null"
],
"format": "date-time"
},
"promoExpires": {
"type": [
"string",
"null"
],
"format": "date-time"
},
"activeFrom": {
"type": [
"string",
"null"
],
"format": "date-time"
},
"activeTo": {
"type": [
"string",
"null"
],
"format": "date-time"
},
"batchTag": {
"type": "string"
},
"notes": {
"type": "string"
}
},
"required": [
"quantity"
],
"additionalProperties": true,
"anyOf": [
{
"required": [
"productId"
]
},
{
"required": [
"product_id"
]
}
]
}
HTTP 201 response (application/json)
{
"type": "object",
"properties": {
"message": {
"type": "string"
},
"count": {
"type": "integer"
},
"product": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"minimum": 1
},
"name": {
"type": "string"
}
},
"additionalProperties": true
},
"serials": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": [
"integer",
"string"
],
"minLength": 1
},
"serial": {
"type": "string"
},
"product_id": {
"type": "integer",
"minimum": 1
},
"product": {
"type": "string"
},
"customer_id": {
"type": [
"integer",
"null"
]
},
"status": {
"type": "string"
},
"redeemed": {
"type": "boolean"
},
"revoked": {
"type": "boolean"
},
"active_activation_count": {
"type": "integer"
},
"max_activations": {
"type": "integer"
},
"remaining_activations": {
"type": "integer"
}
},
"additionalProperties": true
}
}
},
"additionalProperties": true
}
Documented failures: 400, 401, 403, 404, 409, 500, 503.
/api/developer/serials/{serialId}/activate
Apply the activate serial-access action
- Auth
- Account Bearer JWT
- Scope
- Authenticated account, effective developer workspace, applicable permissions and product ownership. Read the operation notes for legacy or owner-only restrictions.
- Request fields
- reason: string
- note: string
- Returns
- HTTP 200: serial, deactivatedActivations.
- Notes
- Changes developer-controlled serial access. It is not a provider refund, customer identity transfer or checkout payment. Revocation/suspension/deactivation can affect existing devices.
Request, response and error reference
Request (application/json)
{
"type": "object",
"properties": {
"reason": {
"type": "string"
},
"note": {
"type": "string"
}
},
"additionalProperties": true
}
HTTP 200 response (application/json)
{
"type": "object",
"properties": {
"serial": {
"type": "object",
"properties": {
"id": {
"type": [
"integer",
"string"
],
"minLength": 1
},
"serial": {
"type": "string"
},
"product_id": {
"type": "integer",
"minimum": 1
},
"product": {
"type": "string"
},
"customer_id": {
"type": [
"integer",
"null"
]
},
"status": {
"type": "string"
},
"redeemed": {
"type": "boolean"
},
"revoked": {
"type": "boolean"
},
"active_activation_count": {
"type": "integer"
},
"max_activations": {
"type": "integer"
},
"remaining_activations": {
"type": "integer"
}
},
"additionalProperties": true
},
"deactivatedActivations": {
"type": "integer"
}
},
"additionalProperties": true
}
Documented failures: 400, 401, 403, 404, 409, 500, 503.
/api/developer/serials/{serialId}/reactivate
Apply the reactivate serial-access action
- Auth
- Account Bearer JWT
- Scope
- Authenticated account, effective developer workspace, applicable permissions and product ownership. Read the operation notes for legacy or owner-only restrictions.
- Request fields
- reason: string
- note: string
- Returns
- HTTP 200: serial, deactivatedActivations.
- Notes
- Changes developer-controlled serial access. It is not a provider refund, customer identity transfer or checkout payment. Revocation/suspension/deactivation can affect existing devices.
Request, response and error reference
Request (application/json)
{
"type": "object",
"properties": {
"reason": {
"type": "string"
},
"note": {
"type": "string"
}
},
"additionalProperties": true
}
HTTP 200 response (application/json)
{
"type": "object",
"properties": {
"serial": {
"type": "object",
"properties": {
"id": {
"type": [
"integer",
"string"
],
"minLength": 1
},
"serial": {
"type": "string"
},
"product_id": {
"type": "integer",
"minimum": 1
},
"product": {
"type": "string"
},
"customer_id": {
"type": [
"integer",
"null"
]
},
"status": {
"type": "string"
},
"redeemed": {
"type": "boolean"
},
"revoked": {
"type": "boolean"
},
"active_activation_count": {
"type": "integer"
},
"max_activations": {
"type": "integer"
},
"remaining_activations": {
"type": "integer"
}
},
"additionalProperties": true
},
"deactivatedActivations": {
"type": "integer"
}
},
"additionalProperties": true
}
Documented failures: 400, 401, 403, 404, 409, 500, 503.
/api/developer/serials/{serialId}/deactivate
Apply the deactivate serial-access action
- Auth
- Account Bearer JWT
- Scope
- Authenticated account, effective developer workspace, applicable permissions and product ownership. Read the operation notes for legacy or owner-only restrictions.
- Request fields
- reason: string
- note: string
- Returns
- HTTP 200: serial, deactivatedActivations.
- Notes
- Changes developer-controlled serial access. It is not a provider refund, customer identity transfer or checkout payment. Revocation/suspension/deactivation can affect existing devices.
Request, response and error reference
Request (application/json)
{
"type": "object",
"properties": {
"reason": {
"type": "string"
},
"note": {
"type": "string"
}
},
"additionalProperties": true
}
HTTP 200 response (application/json)
{
"type": "object",
"properties": {
"serial": {
"type": "object",
"properties": {
"id": {
"type": [
"integer",
"string"
],
"minLength": 1
},
"serial": {
"type": "string"
},
"product_id": {
"type": "integer",
"minimum": 1
},
"product": {
"type": "string"
},
"customer_id": {
"type": [
"integer",
"null"
]
},
"status": {
"type": "string"
},
"redeemed": {
"type": "boolean"
},
"revoked": {
"type": "boolean"
},
"active_activation_count": {
"type": "integer"
},
"max_activations": {
"type": "integer"
},
"remaining_activations": {
"type": "integer"
}
},
"additionalProperties": true
},
"deactivatedActivations": {
"type": "integer"
}
},
"additionalProperties": true
}
Documented failures: 400, 401, 403, 404, 409, 500, 503.
/api/developer/serials/{serialId}/suspend
Apply the suspend serial-access action
- Auth
- Account Bearer JWT
- Scope
- Authenticated account, effective developer workspace, applicable permissions and product ownership. Read the operation notes for legacy or owner-only restrictions.
- Request fields
- reason: string
- note: string
- Returns
- HTTP 200: serial, deactivatedActivations.
- Notes
- Changes developer-controlled serial access. It is not a provider refund, customer identity transfer or checkout payment. Revocation/suspension/deactivation can affect existing devices.
Request, response and error reference
Request (application/json)
{
"type": "object",
"properties": {
"reason": {
"type": "string"
},
"note": {
"type": "string"
}
},
"additionalProperties": true
}
HTTP 200 response (application/json)
{
"type": "object",
"properties": {
"serial": {
"type": "object",
"properties": {
"id": {
"type": [
"integer",
"string"
],
"minLength": 1
},
"serial": {
"type": "string"
},
"product_id": {
"type": "integer",
"minimum": 1
},
"product": {
"type": "string"
},
"customer_id": {
"type": [
"integer",
"null"
]
},
"status": {
"type": "string"
},
"redeemed": {
"type": "boolean"
},
"revoked": {
"type": "boolean"
},
"active_activation_count": {
"type": "integer"
},
"max_activations": {
"type": "integer"
},
"remaining_activations": {
"type": "integer"
}
},
"additionalProperties": true
},
"deactivatedActivations": {
"type": "integer"
}
},
"additionalProperties": true
}
Documented failures: 400, 401, 403, 404, 409, 500, 503.
/api/developer/serials/{serialId}/unsuspend
Apply the unsuspend serial-access action
- Auth
- Account Bearer JWT
- Scope
- Authenticated account, effective developer workspace, applicable permissions and product ownership. Read the operation notes for legacy or owner-only restrictions.
- Request fields
- reason: string
- note: string
- Returns
- HTTP 200: serial, deactivatedActivations.
- Notes
- Changes developer-controlled serial access. It is not a provider refund, customer identity transfer or checkout payment. Revocation/suspension/deactivation can affect existing devices.
Request, response and error reference
Request (application/json)
{
"type": "object",
"properties": {
"reason": {
"type": "string"
},
"note": {
"type": "string"
}
},
"additionalProperties": true
}
HTTP 200 response (application/json)
{
"type": "object",
"properties": {
"serial": {
"type": "object",
"properties": {
"id": {
"type": [
"integer",
"string"
],
"minLength": 1
},
"serial": {
"type": "string"
},
"product_id": {
"type": "integer",
"minimum": 1
},
"product": {
"type": "string"
},
"customer_id": {
"type": [
"integer",
"null"
]
},
"status": {
"type": "string"
},
"redeemed": {
"type": "boolean"
},
"revoked": {
"type": "boolean"
},
"active_activation_count": {
"type": "integer"
},
"max_activations": {
"type": "integer"
},
"remaining_activations": {
"type": "integer"
}
},
"additionalProperties": true
},
"deactivatedActivations": {
"type": "integer"
}
},
"additionalProperties": true
}
Documented failures: 400, 401, 403, 404, 409, 500, 503.
/api/developer/serials/{serialId}/revoke
Apply the revoke serial-access action
- Auth
- Account Bearer JWT
- Scope
- Authenticated account, effective developer workspace, applicable permissions and product ownership. Read the operation notes for legacy or owner-only restrictions.
- Request fields
- reason: string
- note: string
- Returns
- HTTP 200: serial, deactivatedActivations.
- Notes
- Changes developer-controlled serial access. It is not a provider refund, customer identity transfer or checkout payment. Revocation/suspension/deactivation can affect existing devices.
Request, response and error reference
Request (application/json)
{
"type": "object",
"properties": {
"reason": {
"type": "string"
},
"note": {
"type": "string"
}
},
"additionalProperties": true
}
HTTP 200 response (application/json)
{
"type": "object",
"properties": {
"serial": {
"type": "object",
"properties": {
"id": {
"type": [
"integer",
"string"
],
"minLength": 1
},
"serial": {
"type": "string"
},
"product_id": {
"type": "integer",
"minimum": 1
},
"product": {
"type": "string"
},
"customer_id": {
"type": [
"integer",
"null"
]
},
"status": {
"type": "string"
},
"redeemed": {
"type": "boolean"
},
"revoked": {
"type": "boolean"
},
"active_activation_count": {
"type": "integer"
},
"max_activations": {
"type": "integer"
},
"remaining_activations": {
"type": "integer"
}
},
"additionalProperties": true
},
"deactivatedActivations": {
"type": "integer"
}
},
"additionalProperties": true
}
Documented failures: 400, 401, 403, 404, 409, 500, 503.
/api/developer/serials/{serialId}/customer-portal-order/hide
Hide the supported order from customer history
- Auth
- Account Bearer JWT
- Scope
- Authenticated account, effective developer workspace, applicable permissions and product ownership. Read the operation notes for legacy or owner-only restrictions.
- Request fields
- reason: string
- note: string
- Returns
- HTTP 200: serialId, serial, orderId, customerPortalHidden.
- Notes
- Changes history presentation, not product ownership or payment/refund state.
Request, response and error reference
Request (application/json)
{
"type": "object",
"properties": {
"reason": {
"type": "string"
},
"note": {
"type": "string"
}
},
"additionalProperties": true
}
HTTP 200 response (application/json)
{
"type": "object",
"properties": {
"serialId": {
"type": [
"integer",
"string"
],
"minLength": 1
},
"serial": {
"type": "string"
},
"orderId": {
"type": [
"integer",
"string"
],
"minLength": 1
},
"customerPortalHidden": {
"type": "boolean"
}
},
"additionalProperties": true
}
Documented failures: 400, 401, 403, 404, 409, 500, 503.
/api/developer/serials/{serialId}/customer-portal-order/show
Show the supported order in customer history
- Auth
- Account Bearer JWT
- Scope
- Authenticated account, effective developer workspace, applicable permissions and product ownership. Read the operation notes for legacy or owner-only restrictions.
- Request fields
- reason: string
- note: string
- Returns
- HTTP 200: serialId, serial, orderId, customerPortalHidden.
- Notes
- Changes history presentation, not product ownership or payment/refund state.
Request, response and error reference
Request (application/json)
{
"type": "object",
"properties": {
"reason": {
"type": "string"
},
"note": {
"type": "string"
}
},
"additionalProperties": true
}
HTTP 200 response (application/json)
{
"type": "object",
"properties": {
"serialId": {
"type": [
"integer",
"string"
],
"minLength": 1
},
"serial": {
"type": "string"
},
"orderId": {
"type": [
"integer",
"string"
],
"minLength": 1
},
"customerPortalHidden": {
"type": "boolean"
}
},
"additionalProperties": true
}
Documented failures: 400, 401, 403, 404, 409, 500, 503.
/api/developer/purchases/filter-options
Read permitted purchase product and reseller filters
- Auth
- Account Bearer JWT
- Scope
- Authenticated account, effective developer workspace, applicable permissions and product ownership. Read the operation notes for legacy or owner-only restrictions.
- Returns
- HTTP 200: products, resellers.
Request, response and error reference
No request body fields are read by this operation.
HTTP 200 response (application/json)
{
"type": "object",
"properties": {
"products": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"minimum": 1
},
"name": {
"type": "string"
}
},
"additionalProperties": true
}
},
"resellers": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": true,
"description": "Operation-specific extension data; do not put credentials or unnecessary personal information here."
}
}
},
"additionalProperties": true
}
Documented failures: 400, 401, 403, 404, 409, 500, 503.
/api/developer/purchases/manual-grant
Grant authorized product access without collecting payment
- Auth
- Account Bearer JWT
- Scope
- Authenticated account, effective developer workspace, applicable permissions and product ownership. Read the operation notes for legacy or owner-only restrictions.
- Request fields
- productId: integer
- productIds: array
- email: string
- firstName: string
- lastName: string
- customerId: integer
- grantType: string
- grantRequestId: string
- reason: string
- note: string
- serialId: integer
- sendProductPurchaseEmails: boolean
- subscriptionGrantDuration: week | month | three_months | custom | lifetime
- subscriptionGrantEndDate: string
- Returns
- HTTP 201: success, grantType, count, createdCount, skippedCount, created, grants, products, purchases, items, entitlements, serials, historyRecorded, alreadyHadAccess.
- Notes
- Choose explicit products and customer identity. Existing-serial assignment and subscription grants are single-product operations. Reuse grantRequestId only for the same intended grant. A standard product grant can record manual history even when active access already exists; historyRecorded/alreadyHadAccess identify that result. Existing entitlement provenance and serials are retained; this is not a second payment, repeated marketing enrollment or a settlement credit. Subscription grants require subscriptionGrantDuration; custom also requires subscriptionGrantEndDate as YYYY-MM-DD. A timed manual keep-products grant immediately owns the included product snapshot without payment; lifetime grants remain complimentary ongoing access. Future billing requires separate payment setup, preview and customer confirmation. Explicit developer access removal can revoke the manual grant; cancellation or expiry of its subscription does not remove the timed keep-products gift.
Request, response and error reference
Request (application/json)
{
"type": "object",
"properties": {
"productId": {
"type": "integer",
"minimum": 1
},
"productIds": {
"type": "array",
"items": {
"type": "integer",
"minimum": 1
}
},
"email": {
"type": "string",
"format": "email"
},
"firstName": {
"type": "string"
},
"lastName": {
"type": "string"
},
"customerId": {
"type": "integer",
"minimum": 1
},
"grantType": {
"type": "string"
},
"grantRequestId": {
"type": "string"
},
"reason": {
"type": "string"
},
"note": {
"type": "string"
},
"serialId": {
"type": "integer",
"minimum": 1
},
"sendProductPurchaseEmails": {
"type": "boolean"
},
"subscriptionGrantDuration": {
"type": "string",
"enum": [
"week",
"month",
"three_months",
"custom",
"lifetime"
]
},
"subscriptionGrantEndDate": {
"type": "string",
"format": "date"
}
},
"additionalProperties": true
}
HTTP 201 response (application/json)
{
"type": "object",
"properties": {
"success": {
"type": "boolean"
},
"grantType": {
"type": "string"
},
"count": {
"type": "integer"
},
"createdCount": {
"type": "integer"
},
"skippedCount": {
"type": "integer"
},
"created": {
"type": "boolean"
},
"grants": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": true,
"description": "Operation-specific extension data; do not put credentials or unnecessary personal information here."
}
},
"products": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"minimum": 1
},
"name": {
"type": "string"
},
"title": {
"type": "string"
},
"slug": {
"type": [
"string",
"null"
]
},
"description": {
"type": [
"string",
"null"
]
},
"shortDescription": {
"type": [
"string",
"null"
]
},
"price": {
"type": "number"
},
"salePrice": {
"type": [
"number",
"null"
]
},
"regularPrice": {
"type": "number"
},
"displayPrice": {
"type": "number"
},
"priceDisplay": {
"type": "string"
},
"regularPriceDisplay": {
"type": "string"
},
"salePriceDisplay": {
"type": [
"string",
"null"
]
},
"isOnSale": {
"type": "boolean"
},
"currency": {
"type": "string"
},
"imageUrl": {
"type": [
"string",
"null"
]
},
"coverImage": {
"type": [
"string",
"null"
]
},
"developerId": {
"type": "integer",
"minimum": 1
},
"developerName": {
"type": "string"
},
"developer": {
"type": [
"object",
"null"
],
"properties": {
"id": {
"type": "integer",
"minimum": 1
},
"name": {
"type": "string"
},
"slug": {
"type": [
"string",
"null"
]
},
"profileUrl": {
"type": [
"string",
"null"
]
},
"verified": {
"type": "boolean"
}
},
"additionalProperties": true
},
"productType": {
"type": "string"
},
"productTypes": {
"type": "array",
"items": {
"type": "string"
}
},
"categories": {
"type": "array",
"items": {
"type": "string"
}
},
"tags": {
"type": "array",
"items": {
"type": "string"
}
},
"url": {
"type": "string"
},
"subscriptionEnabled": {
"type": "boolean"
},
"billingInterval": {
"type": [
"string",
"null"
]
},
"checkoutEligible": {
"type": "boolean"
},
"capabilities": {
"type": "object",
"additionalProperties": true,
"description": "Operation-specific extension data; do not put credentials or unnecessary personal information here."
},
"requiresActivation": {
"type": "boolean"
},
"supportsSerials": {
"type": "boolean"
},
"supportsDownloads": {
"type": "boolean"
},
"marketplaceAsset": {
"type": [
"object",
"null"
],
"additionalProperties": true,
"description": "Operation-specific extension data; do not put credentials or unnecessary personal information here."
}
},
"additionalProperties": true
}
},
"purchases": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": true,
"description": "Operation-specific extension data; do not put credentials or unnecessary personal information here."
}
},
"items": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": true,
"description": "Operation-specific extension data; do not put credentials or unnecessary personal information here."
}
},
"entitlements": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": true,
"description": "Operation-specific extension data; do not put credentials or unnecessary personal information here."
}
},
"serials": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": [
"integer",
"string"
],
"minLength": 1
},
"serial": {
"type": "string"
},
"product_id": {
"type": "integer",
"minimum": 1
},
"product": {
"type": "string"
},
"customer_id": {
"type": [
"integer",
"null"
]
},
"status": {
"type": "string"
},
"redeemed": {
"type": "boolean"
},
"revoked": {
"type": "boolean"
},
"active_activation_count": {
"type": "integer"
},
"max_activations": {
"type": "integer"
},
"remaining_activations": {
"type": "integer"
}
},
"additionalProperties": true
}
},
"historyRecorded": {
"type": "boolean"
},
"alreadyHadAccess": {
"type": "boolean"
}
},
"additionalProperties": true
}
Documented failures: 400, 401, 403, 404, 409, 500, 503.
/api/developer/customers/{customerId}/activity
Read customer activity
- Auth
- Account Bearer JWT
- Scope
- customers.view and all-products workspace scope; queries stay developer-scoped.
- Request fields
- query limit: integer
- Returns
- HTTP 200: events.
- Notes
- Activity uses camelCase fields; connection and note rows use database-style names. Plugin connections additionally filter fields: customers.view permits customer identity, device_hash and engagement_signal_id; serials.view permits serial_id/serial_code. Opaque failure_reason and metadata require both, otherwise null/{}. Client parameters cannot grant access. Keep permitted diagnostics private. Internal notes are not customer-visible messages. Notes return the latest 100 rows.
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/customers/{customerId}/plugin-connections
Read customer plugin-connection activity
- Auth
- Account Bearer JWT
- Scope
- customers.view and all-products workspace scope; queries stay developer-scoped.
- Request fields
- query limit: integer
- Returns
- HTTP 200: connections.
- Notes
- Activity uses camelCase fields; connection and note rows use database-style names. Plugin connections additionally filter fields: customers.view permits customer identity, device_hash and engagement_signal_id; serials.view permits serial_id/serial_code. Opaque failure_reason and metadata require both, otherwise null/{}. Client parameters cannot grant access. Keep permitted diagnostics private. Internal notes are not customer-visible messages. Notes return the latest 100 rows.
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/customers/{customerId}/notes
Read internal support notes
- Auth
- Account Bearer JWT
- Scope
- customers.view and all-products workspace scope; queries stay developer-scoped.
- Returns
- HTTP 200: notes.
- Notes
- Activity uses camelCase fields; connection and note rows use database-style names. Plugin connections additionally filter fields: customers.view permits customer identity, device_hash and engagement_signal_id; serials.view permits serial_id/serial_code. Opaque failure_reason and metadata require both, otherwise null/{}. Client parameters cannot grant access. Keep permitted diagnostics private. Internal notes are not customer-visible messages. Notes return the latest 100 rows.
Request, response and error reference
No request body fields are read by this operation.
HTTP 200 response (application/json)
{
"type": "object",
"properties": {
"notes": {
"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",
"minimum": 1
},
"author_user_id": {
"type": [
"integer",
"null"
]
},
"note": {
"type": "string"
},
"created_at": {
"type": [
"string",
"null"
],
"format": "date-time"
},
"updated_at": {
"type": [
"string",
"null"
],
"format": "date-time"
}
},
"additionalProperties": true
}
}
},
"additionalProperties": true
}
Documented failures: 400, 401, 403, 404, 409, 500, 503.
/api/developer/customers/{customerId}/notes
Add an internal customer support note
- Auth
- Account Bearer JWT
- Scope
- customers.manage and all-products workspace scope.
- Request fields
- note: string (required)
- Returns
- HTTP 201: note.
- Notes
- Does not send the note to the customer. Avoid credentials, full serials and unnecessary sensitive information.
Request, response and error reference
Request (application/json)
{
"type": "object",
"properties": {
"note": {
"type": "string"
}
},
"required": [
"note"
],
"additionalProperties": true
}
HTTP 201 response (application/json)
{
"type": "object",
"properties": {
"note": {
"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",
"minimum": 1
},
"author_user_id": {
"type": [
"integer",
"null"
]
},
"note": {
"type": "string"
},
"created_at": {
"type": [
"string",
"null"
],
"format": "date-time"
},
"updated_at": {
"type": [
"string",
"null"
],
"format": "date-time"
}
},
"additionalProperties": true
}
},
"additionalProperties": true
}
Documented failures: 400, 401, 403, 404, 409, 500, 503.
/api/developer/customers/{customerId}/reset-activations
Reset eligible customer device activations
- Auth
- Account Bearer JWT
- Scope
- entitlements.manage and all-products workspace scope.
- Request fields
- productId: integer
- Returns
- HTTP 200: reset, serialCount, resetCount.
- Notes
- Read the returned reset counts. A reset is not a refund, a new product grant or permission for recurring billing.
Request, response and error reference
Request (application/json)
{
"type": "object",
"properties": {
"productId": {
"type": "integer",
"minimum": 1
}
},
"additionalProperties": true
}
HTTP 200 response (application/json)
{
"type": "object",
"properties": {
"reset": {
"type": "boolean"
},
"serialCount": {
"type": "integer"
},
"resetCount": {
"type": "integer"
}
},
"additionalProperties": true
}
Documented failures: 400, 401, 403, 404, 409, 500, 503.
/api/developer/customers/{customerId}/resend-library-email
Send the supported customer access email
- Auth
- Account Bearer JWT
- Scope
- customers.manage and all-products workspace scope.
- Request fields
- productId: integer
- Returns
- HTTP 200: email, libraryUrl.
- Notes
- Uses the stored customer identity, not an arbitrary destination email. This is a transactional access message, not marketing enrollment or proof of inbox delivery.
Request, response and error reference
Request (application/json)
{
"type": "object",
"properties": {
"productId": {
"type": "integer",
"minimum": 1
}
},
"additionalProperties": true
}
HTTP 200 response (application/json)
{
"type": "object",
"properties": {
"email": {
"type": "object",
"properties": {
"sent": {
"type": "boolean"
},
"skipped": {
"type": "boolean"
},
"reason": {
"type": "string"
},
"error": {
"type": "string"
},
"providerMessageId": {
"type": [
"string",
"null"
]
}
},
"additionalProperties": true
},
"libraryUrl": {
"type": "string"
}
},
"additionalProperties": true
}
Documented failures: 400, 401, 403, 404, 409, 500, 503.
/api/developer/customers/{customerId}/resend-activation-email
Send the supported customer access email
- Auth
- Account Bearer JWT
- Scope
- customers.manage and all-products workspace scope.
- Request fields
- productId: integer
- Returns
- HTTP 200: email, libraryUrl.
- Notes
- Uses the stored customer identity, not an arbitrary destination email. This is a transactional access message, not marketing enrollment or proof of inbox delivery.
Request, response and error reference
Request (application/json)
{
"type": "object",
"properties": {
"productId": {
"type": "integer",
"minimum": 1
}
},
"additionalProperties": true
}
HTTP 200 response (application/json)
{
"type": "object",
"properties": {
"email": {
"type": "object",
"properties": {
"sent": {
"type": "boolean"
},
"skipped": {
"type": "boolean"
},
"reason": {
"type": "string"
},
"error": {
"type": "string"
},
"providerMessageId": {
"type": [
"string",
"null"
]
}
},
"additionalProperties": true
},
"libraryUrl": {
"type": "string"
}
},
"additionalProperties": true
}
Documented failures: 400, 401, 403, 404, 409, 500, 503.
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.
Permanent gifts and paid subscription ownership
A timed manual keep-products grant gives the customer permanent ownership of the products included when the developer makes that grant, without a payment. That original product snapshot remains owned after subscription cancellation, expiry or incomplete billing setup. Explicit developer access removal can revoke the grant. New products added later are not retroactively included.
A lifetime manual grant instead provides complimentary ongoing subscription access; it is not the timed-grant ownership model or evidence of a paid invoice. Ordinary access-only grants and unpaid checkout trials also do not create paid ownership.
Paid keep-products invoices establish their own product snapshots. Refunding or reversing a paid purchase affects that purchase, not an independent manual ownership grant. Future paid subscription benefits still require the separate billing setup, preview and customer confirmation; a gift is not permission to charge a card.
