API reference
Purchase Options API
Product purchase choices, immutable price and terms versions, scoped deal schedules and checkout selection.
Keep accepted terms intact
Offer terms and prices are versioned. Editing the next offer does not rewrite a customer's accepted purchase snapshot. Use the current offer, offer-version and price-version identifiers at checkout. If terms changed, reload and let the customer review them; do not silently substitute a different offer.
A recurring offer checks out on its own with quantity one. One-time carts stay within one developer and currency. Catalog visibility, storefront visibility, marketplace visibility, publication and existing ownership are separate controls.
For a plan that awards lasting product ownership as invoices are paid, use the ownership subscription-bundle workflow. The new purchase-options editor does not publish keep-products bundles. Access-only subscriptions and earned ownership must not be described as the same thing.
SoundSync
Automatic protected collections
| Choice | What is included |
|---|---|
| Root product only | The root product is included automatically. Do not add its ID to includedProductIds or excludedProductIds. |
| Selected products | Select at least one additional product owned by this workspace. Included and excluded lists cannot overlap or create a circular collection. |
| Linked expansions | Automatic membership uses eligible protected content linked to this instrument, with a published release and recorded availability. |
| Developer catalog | Automatic membership uses eligible published protected-content identities in this workspace, not every ordinary product listing. |
| Include future content | Available only for recurring linked-expansion or developer-catalog choices. Content must meet the same publication and inclusion requirements when it becomes available. |
| Fixed current collection | Keep the saved membership unless you deliberately refresh it. A price edit does not silently add new content; later hiding of a listing is not a command to withdraw already granted access. |
SoundSync
Purchase configuration and deals
/api/products/purchase-options/capabilities
Read purchase-option and protected-content availability
- Auth
- Account Bearer session token
- Scope
- products.view in the effective workspace.
- Returns
- HTTP 200: enabled, checkoutReady, modes, protectedContentEnabled, subscriptionDealDurations, minimumPurchaseMinor.
- Notes
- Current product management verifies workspace permissions and any product ownership/assignment before database writes or AI work. Creating a product or using untargeted new-product AI requires products.create and all-products scope. Existing-product edits/AI use products.edit, file operations use product_files permissions, scheduled-deal writes use marketing.manage, and purchase-option deal publication retains products.publish. Statistics require analytics.view. Publication/archival keep their dedicated permissions. The effective workspace developer owns new products; the teammate remains the audit actor.
Request, response and error reference
No request body fields are read by this operation.
HTTP 200 response (application/json)
{
"type": "object",
"properties": {
"enabled": {
"type": "boolean"
},
"checkoutReady": {
"type": "boolean"
},
"modes": {
"type": "array",
"items": {
"type": "string",
"enum": [
"one_time",
"subscription",
"both"
]
}
},
"protectedContentEnabled": {
"type": "boolean"
},
"subscriptionDealDurations": {
"type": "array",
"items": {
"type": "string"
}
},
"minimumPurchaseMinor": {
"type": "integer",
"minimum": 0
}
},
"additionalProperties": true
}
Documented failures: 400, 401, 403, 404, 409, 500, 503.
/api/products/{id}/purchase-options
Read saved offers, deal history and migration review
- Auth
- Account Bearer session token
- Scope
- Effective developer owns the product; assigned-product access applies. products.view for reads, products.edit for saves, and products.publish for publication, retirement or published-deal changes.
- Returns
- HTTP 200: productId, offers, deals, editorOffers, protectedContentEnabled, migrationReview, migrationNotes.
- Notes
- Configure one or two distinct kinds on one product. New immutable terms/price versions do not rewrite previously accepted customer snapshots. Supply expectedVersionId when editing to detect stale state. Published offers need a published product, price and ready checkout. Published subscriptions use fourteen-day payment recovery and cancellation through the paid period. keep_products publication belongs to the existing ownership subscription-bundle workflow; this editor returns OWNERSHIP_SUBSCRIPTION_BUNDLE_REQUIRED. Future inclusion is limited to recurring linked_expansions/developer_catalog rules. Product ownership spans that product releases; technical content compatibility remains separate. Current product management verifies workspace permissions and any product ownership/assignment before database writes or AI work. Creating a product or using untargeted new-product AI requires products.create and all-products scope. Existing-product edits/AI use products.edit, file operations use product_files permissions, scheduled-deal writes use marketing.manage, and purchase-option deal publication retains products.publish. Statistics require analytics.view. Publication/archival keep their dedicated permissions. The effective workspace developer owns new products; the teammate remains the audit actor.
Request, response and error reference
No request body fields are read by this operation.
HTTP 200 response (application/json)
{
"type": "object",
"properties": {
"productId": {
"type": "integer",
"minimum": 1
},
"offers": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string",
"format": "uuid"
},
"productId": {
"type": "integer",
"minimum": 1
},
"developerId": {
"type": "integer",
"minimum": 1
},
"kind": {
"type": "string",
"enum": [
"one_time",
"subscription"
]
},
"status": {
"type": "string",
"enum": [
"draft",
"published",
"retired"
]
},
"versionId": {
"type": "string",
"format": "uuid"
},
"version": {
"type": "integer",
"minimum": 1
},
"price": {
"anyOf": [
{
"type": "object",
"properties": {
"id": {
"type": "string",
"format": "uuid"
},
"amountMinor": {
"type": "integer",
"minimum": 0,
"description": "Integer minor units, not a floating-dollar amount."
},
"currency": {
"type": "string",
"description": "Three-letter currency code. Managed live checkout currently uses USD."
},
"billingInterval": {
"anyOf": [
{
"type": "string",
"enum": [
"day",
"week",
"month",
"year"
]
},
{
"type": "null"
}
]
},
"intervalCount": {
"type": "integer",
"minimum": 1,
"maximum": 365
},
"renewalPolicy": {
"type": "string",
"enum": [
"not_recurring",
"locked",
"current_list_v1"
]
}
},
"additionalProperties": true
},
{
"type": "null"
}
]
},
"fulfillmentMode": {
"type": "string",
"enum": [
"permanent",
"access",
"keep_products"
]
},
"inclusionScope": {
"type": "string",
"enum": [
"root_only",
"selected_products",
"linked_expansions",
"developer_catalog"
]
},
"includeFuture": {
"type": "boolean"
},
"includedProductIds": {
"type": "array",
"items": {
"type": "integer",
"minimum": 1
}
},
"excludedProductIds": {
"type": "array",
"items": {
"type": "integer",
"minimum": 1
}
},
"terms": {
"type": "object",
"properties": {
"updatePolicy": {
"type": "string",
"enum": [
"existing_policy",
"current_major",
"all_versions"
],
"description": "Older values are accepted but new saved terms normalize to all_versions. Product ownership is not a paid-major gate."
},
"offlinePolicy": {
"type": "string",
"enum": [
"existing_policy",
"permanent_device",
"grace",
"online_only"
]
},
"contentProtection": {
"type": "string",
"enum": [
"protected",
"download_only",
"none"
]
},
"trialScope": {
"type": "string",
"enum": [
"root_only",
"offer_contents"
]
},
"trialDays": {
"type": "integer",
"enum": [
0,
7,
14,
30
]
},
"failedPaymentGraceDays": {
"type": "integer",
"enum": [
0,
3,
7,
14
]
},
"cancellationBehavior": {
"type": "string",
"enum": [
"access_until_period_end",
"lock_immediately"
]
}
},
"additionalProperties": true
},
"membershipPreview": {
"type": "object",
"properties": {},
"additionalProperties": true
}
},
"additionalProperties": true
}
},
"deals": {
"type": "object",
"properties": {},
"additionalProperties": true
},
"editorOffers": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string",
"format": "uuid"
},
"productId": {
"type": "integer",
"minimum": 1
},
"developerId": {
"type": "integer",
"minimum": 1
},
"kind": {
"type": "string",
"enum": [
"one_time",
"subscription"
]
},
"status": {
"type": "string",
"enum": [
"draft",
"published",
"retired"
]
},
"versionId": {
"type": "string",
"format": "uuid"
},
"version": {
"type": "integer",
"minimum": 1
},
"price": {
"anyOf": [
{
"type": "object",
"properties": {
"id": {
"type": "string",
"format": "uuid"
},
"amountMinor": {
"type": "integer",
"minimum": 0,
"description": "Integer minor units, not a floating-dollar amount."
},
"currency": {
"type": "string",
"description": "Three-letter currency code. Managed live checkout currently uses USD."
},
"billingInterval": {
"anyOf": [
{
"type": "string",
"enum": [
"day",
"week",
"month",
"year"
]
},
{
"type": "null"
}
]
},
"intervalCount": {
"type": "integer",
"minimum": 1,
"maximum": 365
},
"renewalPolicy": {
"type": "string",
"enum": [
"not_recurring",
"locked",
"current_list_v1"
]
}
},
"additionalProperties": true
},
{
"type": "null"
}
]
},
"fulfillmentMode": {
"type": "string",
"enum": [
"permanent",
"access",
"keep_products"
]
},
"inclusionScope": {
"type": "string",
"enum": [
"root_only",
"selected_products",
"linked_expansions",
"developer_catalog"
]
},
"includeFuture": {
"type": "boolean"
},
"includedProductIds": {
"type": "array",
"items": {
"type": "integer",
"minimum": 1
}
},
"excludedProductIds": {
"type": "array",
"items": {
"type": "integer",
"minimum": 1
}
},
"terms": {
"type": "object",
"properties": {
"updatePolicy": {
"type": "string",
"enum": [
"existing_policy",
"current_major",
"all_versions"
],
"description": "Older values are accepted but new saved terms normalize to all_versions. Product ownership is not a paid-major gate."
},
"offlinePolicy": {
"type": "string",
"enum": [
"existing_policy",
"permanent_device",
"grace",
"online_only"
]
},
"contentProtection": {
"type": "string",
"enum": [
"protected",
"download_only",
"none"
]
},
"trialScope": {
"type": "string",
"enum": [
"root_only",
"offer_contents"
]
},
"trialDays": {
"type": "integer",
"enum": [
0,
7,
14,
30
]
},
"failedPaymentGraceDays": {
"type": "integer",
"enum": [
0,
3,
7,
14
]
},
"cancellationBehavior": {
"type": "string",
"enum": [
"access_until_period_end",
"lock_immediately"
]
}
},
"additionalProperties": true
},
"membershipPreview": {
"type": "object",
"properties": {},
"additionalProperties": true
}
},
"additionalProperties": true
}
},
"protectedContentEnabled": {
"type": "boolean"
},
"migrationReview": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"migrationNotes": {
"type": "array",
"items": {
"type": "string"
}
}
},
"additionalProperties": true
}
Documented failures: 400, 401, 403, 404, 409, 500, 503.
/api/products/{id}/purchase-options
Save selected purchase options and related deal changes
- Auth
- Account Bearer session token
- Scope
- Effective developer owns the product; assigned-product access applies. products.view for reads, products.edit for saves, and products.publish for publication, retirement or published-deal changes.
- Request fields
- offers: array (required)
- deals: array
- retireOfferIds: array
- Returns
- HTTP 200: offers, deals.
- Notes
- Configure one or two distinct kinds on one product. New immutable terms/price versions do not rewrite previously accepted customer snapshots. Supply expectedVersionId when editing to detect stale state. Published offers need a published product, price and ready checkout. Published subscriptions use fourteen-day payment recovery and cancellation through the paid period. keep_products publication belongs to the existing ownership subscription-bundle workflow; this editor returns OWNERSHIP_SUBSCRIPTION_BUNDLE_REQUIRED. Future inclusion is limited to recurring linked_expansions/developer_catalog rules. Product ownership spans that product releases; technical content compatibility remains separate. Omitted kinds are not retired. Supply explicit retireOfferIds or use the retirement route. Every deals entry needs promotion or retirePromotionId for a kind included in this save. If both are supplied, retirement takes precedence. Automatic linked-expansion/catalog membership uses eligible published protected-content identities, not every ordinary listing. monthly/yearly price inputs normalize to month/year. Current product management verifies workspace permissions and any product ownership/assignment before database writes or AI work. Creating a product or using untargeted new-product AI requires products.create and all-products scope. Existing-product edits/AI use products.edit, file operations use product_files permissions, scheduled-deal writes use marketing.manage, and purchase-option deal publication retains products.publish. Statistics require analytics.view. Publication/archival keep their dedicated permissions. The effective workspace developer owns new products; the teammate remains the audit actor.
Request, response and error reference
Request (application/json)
{
"type": "object",
"properties": {
"offers": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string",
"format": "uuid"
},
"productId": {
"type": "integer",
"minimum": 1
},
"developerId": {
"type": "integer",
"minimum": 1
},
"kind": {
"type": "string",
"enum": [
"one_time",
"subscription"
]
},
"status": {
"type": "string",
"enum": [
"draft",
"published"
]
},
"versionId": {
"type": "string",
"format": "uuid"
},
"version": {
"type": "integer",
"minimum": 1
},
"price": {
"anyOf": [
{
"type": "object",
"properties": {
"id": {
"type": "string",
"format": "uuid"
},
"amountMinor": {
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991
},
"currency": {
"type": "string",
"pattern": "^[A-Za-z]{3}$"
},
"billingInterval": {
"anyOf": [
{
"type": "string",
"enum": [
"day",
"week",
"month",
"year",
"monthly",
"yearly"
],
"description": "monthly/yearly are accepted input aliases; saved responses use month/year."
},
{
"type": "null"
}
]
},
"intervalCount": {
"type": "integer",
"minimum": 1,
"maximum": 365
},
"renewalPolicy": {
"type": "string",
"enum": [
"not_recurring",
"locked",
"current_list_v1"
]
}
},
"additionalProperties": true,
"required": [
"amountMinor"
]
},
{
"type": "null"
}
]
},
"fulfillmentMode": {
"type": "string",
"enum": [
"permanent",
"access",
"keep_products"
]
},
"inclusionScope": {
"type": "string",
"enum": [
"root_only",
"selected_products",
"linked_expansions",
"developer_catalog"
]
},
"includeFuture": {
"type": "boolean"
},
"includedProductIds": {
"type": "array",
"items": {
"type": "integer",
"minimum": 1
},
"maxItems": 10000,
"uniqueItems": true
},
"excludedProductIds": {
"type": "array",
"items": {
"type": "integer",
"minimum": 1
},
"maxItems": 10000,
"uniqueItems": true
},
"terms": {
"type": "object",
"properties": {
"updatePolicy": {
"type": "string",
"enum": [
"existing_policy",
"current_major",
"all_versions"
],
"description": "Older values are accepted but new saved terms normalize to all_versions. Product ownership is not a paid-major gate."
},
"offlinePolicy": {
"type": "string",
"enum": [
"existing_policy",
"permanent_device",
"grace",
"online_only"
]
},
"contentProtection": {
"type": "string",
"enum": [
"protected",
"download_only",
"none"
]
},
"trialScope": {
"type": "string",
"enum": [
"root_only",
"offer_contents"
]
},
"trialDays": {
"type": "integer",
"enum": [
0,
7,
14,
30
]
},
"failedPaymentGraceDays": {
"type": "integer",
"enum": [
0,
3,
7,
14
]
},
"cancellationBehavior": {
"type": "string",
"enum": [
"access_until_period_end",
"lock_immediately"
]
}
},
"additionalProperties": true
},
"membershipPreview": {
"type": "object",
"properties": {},
"additionalProperties": true
},
"expectedVersionId": {
"anyOf": [
{
"type": "string",
"format": "uuid"
},
{
"type": "null"
}
]
},
"refreshCurrentCollection": {
"type": "boolean"
}
},
"additionalProperties": true,
"required": [
"kind"
],
"allOf": [
{
"if": {
"properties": {
"includeFuture": {
"const": true
}
},
"required": [
"includeFuture"
]
},
"then": {
"properties": {
"kind": {
"const": "subscription"
},
"inclusionScope": {
"type": "string",
"enum": [
"linked_expansions",
"developer_catalog"
]
}
},
"required": [
"inclusionScope"
]
}
},
{
"if": {
"anyOf": [
{
"not": {
"required": [
"inclusionScope"
]
}
},
{
"properties": {
"inclusionScope": {
"const": "root_only"
}
},
"required": [
"inclusionScope"
]
}
]
},
"then": {
"properties": {
"includedProductIds": {
"maxItems": 0
},
"excludedProductIds": {
"maxItems": 0
}
}
}
},
{
"if": {
"properties": {
"kind": {
"const": "one_time"
}
},
"required": [
"kind"
]
},
"then": {
"properties": {
"fulfillmentMode": {
"const": "permanent"
},
"price": {
"anyOf": [
{
"type": "null"
},
{
"type": "object",
"properties": {
"billingInterval": {
"type": "null"
},
"intervalCount": {
"const": 1
},
"renewalPolicy": {
"const": "not_recurring"
}
}
}
]
}
}
}
},
{
"if": {
"properties": {
"kind": {
"const": "subscription"
}
},
"required": [
"kind"
]
},
"then": {
"properties": {
"fulfillmentMode": {
"type": "string",
"enum": [
"access",
"keep_products"
]
},
"terms": {
"properties": {
"offlinePolicy": {
"type": "string",
"enum": [
"existing_policy",
"grace",
"online_only"
]
}
}
},
"price": {
"anyOf": [
{
"type": "null"
},
{
"type": "object",
"properties": {
"amountMinor": {
"minimum": 1
},
"billingInterval": {
"type": "string",
"enum": [
"day",
"week",
"month",
"year",
"monthly",
"yearly"
]
},
"renewalPolicy": {
"type": "string",
"enum": [
"locked",
"current_list_v1"
]
}
}
}
]
}
}
}
},
{
"if": {
"properties": {
"inclusionScope": {
"const": "selected_products"
}
},
"required": [
"inclusionScope"
]
},
"then": {
"properties": {
"includedProductIds": {
"minItems": 1
}
},
"required": [
"includedProductIds"
]
}
},
{
"if": {
"properties": {
"status": {
"const": "published"
}
},
"required": [
"status"
]
},
"then": {
"properties": {
"price": {
"type": "object"
}
},
"required": [
"price"
]
}
},
{
"if": {
"properties": {
"kind": {
"const": "subscription"
},
"status": {
"const": "published"
}
},
"required": [
"kind",
"status"
]
},
"then": {
"properties": {
"fulfillmentMode": {
"const": "access"
},
"terms": {
"properties": {
"failedPaymentGraceDays": {
"const": 14
},
"cancellationBehavior": {
"const": "access_until_period_end"
}
}
}
}
}
}
]
},
"minItems": 1,
"maxItems": 2,
"allOf": [
{
"contains": {
"properties": {
"kind": {
"const": "one_time"
}
},
"required": [
"kind"
]
},
"minContains": 0,
"maxContains": 1
},
{
"contains": {
"properties": {
"kind": {
"const": "subscription"
}
},
"required": [
"kind"
]
},
"minContains": 0,
"maxContains": 1
}
]
},
"deals": {
"type": "array",
"maxItems": 100,
"items": {
"type": "object",
"properties": {
"kind": {
"type": "string",
"enum": [
"one_time",
"subscription"
]
},
"promotion": {
"type": "object",
"properties": {
"id": {
"type": "string",
"format": "uuid"
},
"offerId": {
"type": "string",
"format": "uuid"
},
"campaignId": {
"anyOf": [
{
"type": "integer",
"minimum": 1
},
{
"type": "null"
}
]
},
"status": {
"type": "string",
"enum": [
"active",
"retired"
]
},
"title": {
"type": "string",
"minLength": 1,
"maxLength": 200,
"pattern": "\\S"
},
"discountType": {
"type": "string",
"enum": [
"percent_bps",
"amount_minor"
]
},
"discountValue": {
"type": "integer",
"minimum": 1,
"maximum": 9007199254740991
},
"currency": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"duration": {
"type": "string",
"enum": [
"first_period",
"limited_periods",
"ongoing"
]
},
"durationPeriods": {
"anyOf": [
{
"type": "integer",
"minimum": 1,
"maximum": 1200
},
{
"type": "null"
}
]
},
"startsAt": {
"type": "string",
"format": "date-time"
},
"endsAt": {
"anyOf": [
{
"type": "string",
"format": "date-time"
},
{
"type": "null"
}
]
},
"couponCode": {
"anyOf": [
{
"type": "string",
"pattern": "^[A-Za-z0-9_-]{0,64}$"
},
{
"type": "null"
}
]
},
"stackingPolicy": {
"type": "string",
"enum": [
"exclusive",
"with_sale"
]
},
"eligibility": {
"type": "object",
"properties": {
"newCustomersOnly": {
"type": "boolean"
},
"returningCustomersAllowed": {
"type": "boolean"
}
},
"additionalProperties": false
},
"replacesPromotionId": {
"type": "string",
"format": "uuid"
}
},
"additionalProperties": true,
"required": [
"title",
"discountType",
"discountValue",
"startsAt"
],
"allOf": [
{
"if": {
"properties": {
"discountType": {
"const": "amount_minor"
}
},
"required": [
"discountType"
]
},
"then": {
"properties": {
"currency": {
"type": "string",
"pattern": "^[A-Za-z]{3}$"
}
},
"required": [
"currency"
]
}
},
{
"if": {
"properties": {
"discountType": {
"const": "percent_bps"
}
},
"required": [
"discountType"
]
},
"then": {
"properties": {
"discountValue": {
"maximum": 10000
}
}
}
},
{
"if": {
"properties": {
"duration": {
"const": "limited_periods"
}
},
"required": [
"duration"
]
},
"then": {
"properties": {
"durationPeriods": {
"type": "integer",
"minimum": 1,
"maximum": 1200
}
},
"required": [
"durationPeriods"
]
}
},
{
"if": {
"properties": {
"duration": {
"const": "ongoing"
}
},
"required": [
"duration"
]
},
"then": {
"properties": {
"durationPeriods": {
"type": "null"
}
}
}
},
{
"if": {
"anyOf": [
{
"not": {
"required": [
"duration"
]
}
},
{
"properties": {
"duration": {
"const": "first_period"
}
},
"required": [
"duration"
]
}
]
},
"then": {
"properties": {
"durationPeriods": {
"anyOf": [
{
"const": 1
},
{
"type": "null"
}
]
}
}
}
}
]
},
"retirePromotionId": {
"type": "string",
"format": "uuid"
}
},
"additionalProperties": true,
"required": [
"kind"
],
"anyOf": [
{
"required": [
"promotion"
]
},
{
"required": [
"retirePromotionId"
]
}
],
"allOf": [
{
"if": {
"properties": {
"kind": {
"const": "one_time"
}
},
"required": [
"kind"
]
},
"then": {
"properties": {
"promotion": {
"properties": {
"duration": {
"const": "first_period"
},
"durationPeriods": {
"anyOf": [
{
"const": 1
},
{
"type": "null"
}
]
}
}
}
}
}
}
]
}
},
"retireOfferIds": {
"type": "array",
"items": {
"type": "string",
"format": "uuid"
},
"maxItems": 2
}
},
"additionalProperties": true,
"required": [
"offers"
]
}
HTTP 200 response (application/json)
{
"type": "object",
"properties": {
"offers": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string",
"format": "uuid"
},
"productId": {
"type": "integer",
"minimum": 1
},
"developerId": {
"type": "integer",
"minimum": 1
},
"kind": {
"type": "string",
"enum": [
"one_time",
"subscription"
]
},
"status": {
"type": "string",
"enum": [
"draft",
"published",
"retired"
]
},
"versionId": {
"type": "string",
"format": "uuid"
},
"version": {
"type": "integer",
"minimum": 1
},
"price": {
"anyOf": [
{
"type": "object",
"properties": {
"id": {
"type": "string",
"format": "uuid"
},
"amountMinor": {
"type": "integer",
"minimum": 0,
"description": "Integer minor units, not a floating-dollar amount."
},
"currency": {
"type": "string",
"description": "Three-letter currency code. Managed live checkout currently uses USD."
},
"billingInterval": {
"anyOf": [
{
"type": "string",
"enum": [
"day",
"week",
"month",
"year"
]
},
{
"type": "null"
}
]
},
"intervalCount": {
"type": "integer",
"minimum": 1,
"maximum": 365
},
"renewalPolicy": {
"type": "string",
"enum": [
"not_recurring",
"locked",
"current_list_v1"
]
}
},
"additionalProperties": true
},
{
"type": "null"
}
]
},
"fulfillmentMode": {
"type": "string",
"enum": [
"permanent",
"access",
"keep_products"
]
},
"inclusionScope": {
"type": "string",
"enum": [
"root_only",
"selected_products",
"linked_expansions",
"developer_catalog"
]
},
"includeFuture": {
"type": "boolean"
},
"includedProductIds": {
"type": "array",
"items": {
"type": "integer",
"minimum": 1
}
},
"excludedProductIds": {
"type": "array",
"items": {
"type": "integer",
"minimum": 1
}
},
"terms": {
"type": "object",
"properties": {
"updatePolicy": {
"type": "string",
"enum": [
"existing_policy",
"current_major",
"all_versions"
],
"description": "Older values are accepted but new saved terms normalize to all_versions. Product ownership is not a paid-major gate."
},
"offlinePolicy": {
"type": "string",
"enum": [
"existing_policy",
"permanent_device",
"grace",
"online_only"
]
},
"contentProtection": {
"type": "string",
"enum": [
"protected",
"download_only",
"none"
]
},
"trialScope": {
"type": "string",
"enum": [
"root_only",
"offer_contents"
]
},
"trialDays": {
"type": "integer",
"enum": [
0,
7,
14,
30
]
},
"failedPaymentGraceDays": {
"type": "integer",
"enum": [
0,
3,
7,
14
]
},
"cancellationBehavior": {
"type": "string",
"enum": [
"access_until_period_end",
"lock_immediately"
]
}
},
"additionalProperties": true
},
"membershipPreview": {
"type": "object",
"properties": {},
"additionalProperties": true
}
},
"additionalProperties": true
}
},
"deals": {
"type": "array",
"items": {
"anyOf": [
{
"type": "object",
"properties": {
"id": {
"type": "string",
"format": "uuid"
},
"offerId": {
"type": "string",
"format": "uuid"
},
"campaignId": {
"anyOf": [
{
"type": "integer",
"minimum": 1
},
{
"type": "null"
}
]
},
"status": {
"type": "string",
"enum": [
"active",
"retired"
]
},
"title": {
"type": "string",
"maxLength": 200
},
"discountType": {
"type": "string",
"enum": [
"percent_bps",
"amount_minor"
]
},
"discountValue": {
"type": "integer",
"minimum": 1
},
"currency": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"duration": {
"type": "string",
"enum": [
"first_period",
"limited_periods",
"ongoing"
]
},
"durationPeriods": {
"anyOf": [
{
"type": "integer",
"minimum": 1,
"maximum": 1200
},
{
"type": "null"
}
]
},
"startsAt": {
"type": "string",
"format": "date-time"
},
"endsAt": {
"anyOf": [
{
"type": "string",
"format": "date-time"
},
{
"type": "null"
}
]
},
"couponCode": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"stackingPolicy": {
"type": "string",
"enum": [
"exclusive",
"with_sale"
]
},
"eligibility": {
"type": "object",
"properties": {
"newCustomersOnly": {
"type": "boolean"
},
"returningCustomersAllowed": {
"type": "boolean"
}
},
"additionalProperties": true
}
},
"additionalProperties": true
},
{
"type": "object",
"properties": {
"id": {
"type": "string",
"format": "uuid"
},
"status": {
"const": "retired"
}
},
"additionalProperties": true,
"required": [
"id",
"status"
]
}
]
}
}
},
"additionalProperties": true
}
Documented failures: 400, 401, 403, 404, 409, 500, 503.
Operation errors: PURCHASE_OPTIONS_UNAVAILABLE, OFFER_CHANGED, OFFER_CHECKOUT_NOT_READY, PRODUCT_NOT_PUBLISHED, PROTECTED_RELEASE_REQUIRED, OWNERSHIP_SUBSCRIPTION_BUNDLE_REQUIRED, PURCHASE_OPTION_CONFLICT.
/api/products/{id}/purchase-options/{offerId}
Retire an offer without deleting accepted customer terms
- Auth
- Account Bearer session token
- Scope
- Effective developer owns the product; assigned-product access applies. products.view for reads, products.edit for saves, and products.publish for publication, retirement or published-deal changes.
- Returns
- HTTP 200: id, status.
- Notes
- Configure one or two distinct kinds on one product. New immutable terms/price versions do not rewrite previously accepted customer snapshots. Supply expectedVersionId when editing to detect stale state. Published offers need a published product, price and ready checkout. Published subscriptions use fourteen-day payment recovery and cancellation through the paid period. keep_products publication belongs to the existing ownership subscription-bundle workflow; this editor returns OWNERSHIP_SUBSCRIPTION_BUNDLE_REQUIRED. Future inclusion is limited to recurring linked_expansions/developer_catalog rules. Product ownership spans that product releases; technical content compatibility remains separate. Returns only id and status; GET the configuration to read the retained terms. Current product management verifies workspace permissions and any product ownership/assignment before database writes or AI work. Creating a product or using untargeted new-product AI requires products.create and all-products scope. Existing-product edits/AI use products.edit, file operations use product_files permissions, scheduled-deal writes use marketing.manage, and purchase-option deal publication retains products.publish. Statistics require analytics.view. Publication/archival keep their dedicated permissions. The effective workspace developer owns new products; the teammate remains the audit actor.
Request, response and error reference
No request body fields are read by this operation.
HTTP 200 response (application/json)
{
"type": "object",
"properties": {
"id": {
"type": "string",
"format": "uuid"
},
"status": {
"const": "retired"
}
},
"additionalProperties": true,
"required": [
"id",
"status"
]
}
Documented failures: 400, 401, 403, 404, 409, 500, 503.
/api/products/{id}/purchase-options/{offerId}/deals
Read the selected offer deals including retired entries
- Auth
- Account Bearer session token
- Scope
- Effective developer owns the product; assigned-product access applies. products.view for reads, products.edit for saves, and products.publish for publication, retirement or published-deal changes.
- Returns
- HTTP 200: deals.
- Notes
- Current product management verifies workspace permissions and any product ownership/assignment before database writes or AI work. Creating a product or using untargeted new-product AI requires products.create and all-products scope. Existing-product edits/AI use products.edit, file operations use product_files permissions, scheduled-deal writes use marketing.manage, and purchase-option deal publication retains products.publish. Statistics require analytics.view. Publication/archival keep their dedicated permissions. The effective workspace developer owns new products; the teammate remains the audit actor.
Request, response and error reference
No request body fields are read by this operation.
HTTP 200 response (application/json)
{
"type": "object",
"properties": {
"deals": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string",
"format": "uuid"
},
"offerId": {
"type": "string",
"format": "uuid"
},
"campaignId": {
"anyOf": [
{
"type": "integer",
"minimum": 1
},
{
"type": "null"
}
]
},
"status": {
"type": "string",
"enum": [
"active",
"retired"
]
},
"title": {
"type": "string",
"maxLength": 200
},
"discountType": {
"type": "string",
"enum": [
"percent_bps",
"amount_minor"
]
},
"discountValue": {
"type": "integer",
"minimum": 1
},
"currency": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"duration": {
"type": "string",
"enum": [
"first_period",
"limited_periods",
"ongoing"
]
},
"durationPeriods": {
"anyOf": [
{
"type": "integer",
"minimum": 1,
"maximum": 1200
},
{
"type": "null"
}
]
},
"startsAt": {
"type": "string",
"format": "date-time"
},
"endsAt": {
"anyOf": [
{
"type": "string",
"format": "date-time"
},
{
"type": "null"
}
]
},
"couponCode": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"stackingPolicy": {
"type": "string",
"enum": [
"exclusive",
"with_sale"
]
},
"eligibility": {
"type": "object",
"properties": {
"newCustomersOnly": {
"type": "boolean"
},
"returningCustomersAllowed": {
"type": "boolean"
}
},
"additionalProperties": true
}
},
"additionalProperties": true
}
}
},
"additionalProperties": true
}
Documented failures: 400, 401, 403, 404, 409, 500, 503.
/api/products/{id}/purchase-options/{offerId}/deals
Create a versioned deal for one purchase option
- Auth
- Account Bearer session token
- Scope
- Effective developer owns the product; assigned-product access applies. products.view for reads, products.edit for saves, and products.publish for publication, retirement or published-deal changes.
- Request fields
- id: string
- offerId: string
- campaignId: value
- status: active | retired
- title: string (required)
- discountType: percent_bps | amount_minor (required)
- discountValue: integer (required)
- currency: value
- duration: first_period | limited_periods | ongoing
- durationPeriods: value
- startsAt: string (required)
- endsAt: value
- couponCode: value
- stackingPolicy: exclusive | with_sale
- eligibility: object
- replacesPromotionId: string
- Returns
- HTTP 200: id, offerId, campaignId, status, title, discountType, discountValue, currency, duration, durationPeriods, startsAt, endsAt, couponCode, stackingPolicy, eligibility.
- Notes
- Percent values are basis points, not whole percentages. A fixed discount uses integer minor units and matching currency. Starts and ends are timestamps; end must follow start. One-time deals cover one purchase. Recurring deals distinguish first_period, limited_periods and ongoing. Versioned automatic deals and subscription payments retain their own minimum checks; a one-time coupon reduction is checked against the final paid cart. replacesPromotionId identifies a saved deal replaced by this new immutable record. Current product management verifies workspace permissions and any product ownership/assignment before database writes or AI work. Creating a product or using untargeted new-product AI requires products.create and all-products scope. Existing-product edits/AI use products.edit, file operations use product_files permissions, scheduled-deal writes use marketing.manage, and purchase-option deal publication retains products.publish. Statistics require analytics.view. Publication/archival keep their dedicated permissions. The effective workspace developer owns new products; the teammate remains the audit actor.
Request, response and error reference
Request (application/json)
{
"type": "object",
"properties": {
"id": {
"type": "string",
"format": "uuid"
},
"offerId": {
"type": "string",
"format": "uuid"
},
"campaignId": {
"anyOf": [
{
"type": "integer",
"minimum": 1
},
{
"type": "null"
}
]
},
"status": {
"type": "string",
"enum": [
"active",
"retired"
]
},
"title": {
"type": "string",
"minLength": 1,
"maxLength": 200,
"pattern": "\\S"
},
"discountType": {
"type": "string",
"enum": [
"percent_bps",
"amount_minor"
]
},
"discountValue": {
"type": "integer",
"minimum": 1,
"maximum": 9007199254740991
},
"currency": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"duration": {
"type": "string",
"enum": [
"first_period",
"limited_periods",
"ongoing"
]
},
"durationPeriods": {
"anyOf": [
{
"type": "integer",
"minimum": 1,
"maximum": 1200
},
{
"type": "null"
}
]
},
"startsAt": {
"type": "string",
"format": "date-time"
},
"endsAt": {
"anyOf": [
{
"type": "string",
"format": "date-time"
},
{
"type": "null"
}
]
},
"couponCode": {
"anyOf": [
{
"type": "string",
"pattern": "^[A-Za-z0-9_-]{0,64}$"
},
{
"type": "null"
}
]
},
"stackingPolicy": {
"type": "string",
"enum": [
"exclusive",
"with_sale"
]
},
"eligibility": {
"type": "object",
"properties": {
"newCustomersOnly": {
"type": "boolean"
},
"returningCustomersAllowed": {
"type": "boolean"
}
},
"additionalProperties": false
},
"replacesPromotionId": {
"type": "string",
"format": "uuid"
}
},
"additionalProperties": true,
"required": [
"title",
"discountType",
"discountValue",
"startsAt"
],
"allOf": [
{
"if": {
"properties": {
"discountType": {
"const": "amount_minor"
}
},
"required": [
"discountType"
]
},
"then": {
"properties": {
"currency": {
"type": "string",
"pattern": "^[A-Za-z]{3}$"
}
},
"required": [
"currency"
]
}
},
{
"if": {
"properties": {
"discountType": {
"const": "percent_bps"
}
},
"required": [
"discountType"
]
},
"then": {
"properties": {
"discountValue": {
"maximum": 10000
}
}
}
},
{
"if": {
"properties": {
"duration": {
"const": "limited_periods"
}
},
"required": [
"duration"
]
},
"then": {
"properties": {
"durationPeriods": {
"type": "integer",
"minimum": 1,
"maximum": 1200
}
},
"required": [
"durationPeriods"
]
}
},
{
"if": {
"properties": {
"duration": {
"const": "ongoing"
}
},
"required": [
"duration"
]
},
"then": {
"properties": {
"durationPeriods": {
"type": "null"
}
}
}
},
{
"if": {
"anyOf": [
{
"not": {
"required": [
"duration"
]
}
},
{
"properties": {
"duration": {
"const": "first_period"
}
},
"required": [
"duration"
]
}
]
},
"then": {
"properties": {
"durationPeriods": {
"anyOf": [
{
"const": 1
},
{
"type": "null"
}
]
}
}
}
}
]
}
HTTP 200 response (application/json)
{
"type": "object",
"properties": {
"id": {
"type": "string",
"format": "uuid"
},
"offerId": {
"type": "string",
"format": "uuid"
},
"campaignId": {
"anyOf": [
{
"type": "integer",
"minimum": 1
},
{
"type": "null"
}
]
},
"status": {
"type": "string",
"enum": [
"active",
"retired"
]
},
"title": {
"type": "string",
"maxLength": 200
},
"discountType": {
"type": "string",
"enum": [
"percent_bps",
"amount_minor"
]
},
"discountValue": {
"type": "integer",
"minimum": 1
},
"currency": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"duration": {
"type": "string",
"enum": [
"first_period",
"limited_periods",
"ongoing"
]
},
"durationPeriods": {
"anyOf": [
{
"type": "integer",
"minimum": 1,
"maximum": 1200
},
{
"type": "null"
}
]
},
"startsAt": {
"type": "string",
"format": "date-time"
},
"endsAt": {
"anyOf": [
{
"type": "string",
"format": "date-time"
},
{
"type": "null"
}
]
},
"couponCode": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
]
},
"stackingPolicy": {
"type": "string",
"enum": [
"exclusive",
"with_sale"
]
},
"eligibility": {
"type": "object",
"properties": {
"newCustomersOnly": {
"type": "boolean"
},
"returningCustomersAllowed": {
"type": "boolean"
}
},
"additionalProperties": true
}
},
"additionalProperties": true
}
Documented failures: 400, 401, 403, 404, 409, 500, 503.
/api/products/{id}/purchase-options/{offerId}/deals/{promotionId}
Retire a deal without rewriting accepted subscription pricing
- Auth
- Account Bearer session token
- Scope
- Effective developer owns the product; assigned-product access applies. products.view for reads, products.edit for saves, and products.publish for publication, retirement or published-deal changes.
- Returns
- HTTP 200: id, status.
- Notes
- Returns only id and status, not a complete deal record. Read the selected offer deals separately for retained history. Current product management verifies workspace permissions and any product ownership/assignment before database writes or AI work. Creating a product or using untargeted new-product AI requires products.create and all-products scope. Existing-product edits/AI use products.edit, file operations use product_files permissions, scheduled-deal writes use marketing.manage, and purchase-option deal publication retains products.publish. Statistics require analytics.view. Publication/archival keep their dedicated permissions. The effective workspace developer owns new products; the teammate remains the audit actor.
Request, response and error reference
No request body fields are read by this operation.
HTTP 200 response (application/json)
{
"type": "object",
"properties": {
"id": {
"type": "string",
"format": "uuid"
},
"status": {
"const": "retired"
}
},
"additionalProperties": true,
"required": [
"id",
"status"
]
}
Documented failures: 400, 401, 403, 404, 409, 500, 503.
SoundSync
Read the saved product choices
curl --fail-with-body -sS "$SOUNDSYNC_API_BASE/api/products/$PRODUCT_ID/purchase-options" \
-H "Authorization: Bearer $SOUNDSYNC_ACCOUNT_TOKEN"
SoundSync
Illustrative unpublished offer body
{
"offers": [
{
"kind": "subscription",
"status": "draft",
"fulfillmentMode": "access",
"inclusionScope": "root_only",
"includeFuture": false,
"terms": {
"offlinePolicy": "grace",
"trialDays": 14,
"failedPaymentGraceDays": 14,
"cancellationBehavior": "access_until_period_end"
},
"price": {
"amountMinor": 1999,
"currency": "usd",
"billingInterval": "month",
"intervalCount": 1,
"renewalPolicy": "locked"
}
}
]
}
SoundSync
Save and checkout identifiers
| Field | Use |
|---|---|
| expectedVersionId | Supply the saved offer version when editing; stale state returns OFFER_CHANGED. |
| offerId, offerVersionId, priceVersionId | Use current public-catalog values for the selected choice at checkout. A conflict requires review, not an automatic replacement. |
| amountMinor / percent_bps | Integer currency minor units for prices and fixed deals; basis points for percentage deals. These are not floating-dollar price fields. |
| offers | Save one or two distinct kinds. Omitting an existing kind does not retire it. Draft choices can be incomplete; publication requires a saved price and the supported recurring terms. |
| deals | Each action names a kind included in this save and supplies promotion or retirePromotionId. Use one action per entry; if both fields are supplied, retirement takes precedence. |
| retireOfferIds / retirePromotionId | Explicitly retire the saved reference. Retirement does not delete accepted customer history. |
| refreshCurrentCollection | Deliberate refresh of a fixed current collection, not an implicit effect of changing the price. |
SoundSync
Related contracts
SoundSync
Choose how the product is sold
One listing can expose buy-once and recurring choices. The captured editor uses example prices; accepted customer terms remain separate from your next draft.
