Guide
Before-Purchase Offers and Product Marketing
Configure one optional offers page before cart review, with global defaults, product overrides and verified rewards.
Offer compatible extras before checkout
Website Builder provides a before-purchase offers page with optional add-ons and an optional signup reward. Product Marketing settings can replace the global page when a configured product is in the cart. Matching product offers combine into one page before cart review rather than a chain of repeated popups.
The page can be reached through the store's /offers route, including /storefronts/:slug/offers on the hosted path. Cart and View cart entry points use the same before-purchase flow. Only published, visible, sellable choices that meet the cart requirements are offered; checkout still calculates the authoritative price.
SoundSync
Build a relevant before-purchase page
-
Create the website
Configure the global page in Website Builder. A product-specific Marketing tab requires an existing website.
-
Choose the presentation
Set heading, supporting text, continue label and grid, stacked or featured layout. Choose whether the page appears automatically before checkout.
-
Select optional deals
Add up to 12 distinct products with the relevant copy and badges. The page product and expansion parent requirements are included automatically; add any additional required products deliberately.
-
Add a reward if useful
Choose an optional signup section and one supported reward. A free-product reward needs verified email before delivery and counts toward external redemptions. Reward coupons are discounts, not cash or stored-value balances.
-
Preview the real cart
Check carts with and without each required product, unavailable or already-added extras, a product-specific override and the route to final checkout. Customers can continue without accepting optional extras.
-
Save without overwriting another edit
Product Marketing uses the current Website Builder revision. If another edit wins first, reload and review the conflict before saving again.
Permissions and customer information
Reading product marketing uses the existing product-view permission and assigned-product scope. Saving needs product editing and storefront management. Required products and reward products stay within the teammate's product scope; gift-card reward configuration needs all-products scope.
Purchases and storefront signup automatically add customers to the relevant marketing list, without a separate opt-in checkbox. Saved unsubscribes, complaints, refusals and suppressions remain protected. Reward verification is an inbox/access check, not permission to erase a saved restriction.
SoundSync
Product-specific page configuration
/api/products/{id}/marketing
Read product-specific before-purchase page settings
- Auth
- Account Bearer session token
- Scope
- products.view and assigned-product access.
- Returns
- HTTP 200: productId, productName, revision, configuration, products, rewards, storefront.
- Notes
- Website Builder must already have a website. PUT submits the complete configuration with the current website revision; a stale revision returns 409 STOREFRONT_EDIT_CONFLICT. This edits product marketing, not product price, customer consent or checkout authority. Preserve the full normalized signup and design fields returned by GET. Choose one signup reward, not both a product and coupon. Product and parent requirements are retained automatically. Unknown extension fields do not bypass server validation. 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
},
"productName": {
"type": "string"
},
"revision": {
"type": "integer",
"minimum": 0
},
"configuration": {
"type": "object",
"properties": {
"productId": {
"type": "integer",
"minimum": 1
},
"enabled": {
"type": "boolean"
},
"showBeforeCheckout": {
"type": "boolean"
},
"heading": {
"type": "string",
"maxLength": 100
},
"body": {
"type": "string",
"maxLength": 400
},
"continueLabel": {
"type": "string",
"maxLength": 40
},
"layout": {
"type": "string",
"enum": [
"grid",
"stacked",
"featured"
]
},
"offers": {
"type": "array",
"maxItems": 12,
"items": {
"type": "object",
"properties": {
"id": {
"type": "string",
"pattern": "^[A-Za-z0-9_-]+$",
"maxLength": 64
},
"productId": {
"type": "integer",
"minimum": 1
},
"heading": {
"type": "string",
"maxLength": 100
},
"body": {
"type": "string",
"maxLength": 240
},
"badge": {
"type": "string",
"maxLength": 32
},
"requiredProductIds": {
"type": "array",
"maxItems": 14,
"uniqueItems": true,
"items": {
"type": "integer",
"minimum": 1
}
}
},
"additionalProperties": true,
"required": [
"id",
"productId"
]
}
},
"signupEnabled": {
"type": "boolean"
},
"signup": {
"type": "object",
"properties": {
"reward": {
"type": "object",
"properties": {
"productEnabled": {
"type": "boolean"
},
"productId": {
"anyOf": [
{
"type": "integer",
"minimum": 1
},
{
"type": "null"
}
]
},
"couponEnabled": {
"type": "boolean"
},
"offerId": {
"anyOf": [
{
"type": "integer",
"minimum": 1
},
{
"type": "null"
}
]
}
},
"additionalProperties": true
}
},
"additionalProperties": true
}
},
"additionalProperties": true
},
"products": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"minimum": 1
},
"name": {
"type": "string"
}
},
"additionalProperties": true
}
},
"rewards": {
"type": "object",
"properties": {
"products": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"minimum": 1
},
"name": {
"type": "string"
}
},
"additionalProperties": true
}
},
"offers": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"minimum": 1
},
"name": {
"type": "string"
}
},
"additionalProperties": true
}
}
},
"additionalProperties": true
},
"storefront": {
"type": "object",
"properties": {},
"additionalProperties": true
}
},
"additionalProperties": true
}
Documented failures: 400, 401, 403, 404, 409, 500, 503.
Operation errors: MARKETING_WEBSITE_REQUIRED, PRODUCT_MARKETING_INVALID, STOREFRONT_EDIT_CONFLICT, PRE_PURCHASE_PRODUCT_UNAVAILABLE.
/api/products/{id}/marketing
Save product-specific before-purchase page settings
- Auth
- Account Bearer session token
- Scope
- products.edit plus storefront.manage and assigned-product access; gift-card rewards require all-products scope.
- Request fields
- revision: integer (required)
- configuration: object (required)
- Returns
- HTTP 200: configuration, revision.
- Notes
- Website Builder must already have a website. PUT submits the complete configuration with the current website revision; a stale revision returns 409 STOREFRONT_EDIT_CONFLICT. This edits product marketing, not product price, customer consent or checkout authority. Preserve the full normalized signup and design fields returned by GET. Choose one signup reward, not both a product and coupon. Product and parent requirements are retained automatically. Unknown extension fields do not bypass server validation. 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": {
"revision": {
"type": "integer",
"minimum": 0
},
"configuration": {
"type": "object",
"properties": {
"productId": {
"type": "integer",
"minimum": 1
},
"enabled": {
"type": "boolean"
},
"showBeforeCheckout": {
"type": "boolean"
},
"heading": {
"type": "string",
"maxLength": 100
},
"body": {
"type": "string",
"maxLength": 400
},
"continueLabel": {
"type": "string",
"maxLength": 40
},
"layout": {
"type": "string",
"enum": [
"grid",
"stacked",
"featured"
]
},
"offers": {
"type": "array",
"maxItems": 12,
"items": {
"type": "object",
"properties": {
"id": {
"type": "string",
"pattern": "^[A-Za-z0-9_-]+$",
"maxLength": 64
},
"productId": {
"type": "integer",
"minimum": 1
},
"heading": {
"type": "string",
"maxLength": 100
},
"body": {
"type": "string",
"maxLength": 240
},
"badge": {
"type": "string",
"maxLength": 32
},
"requiredProductIds": {
"type": "array",
"maxItems": 14,
"uniqueItems": true,
"items": {
"type": "integer",
"minimum": 1
}
}
},
"additionalProperties": true,
"required": [
"id",
"productId"
]
}
},
"signupEnabled": {
"type": "boolean"
},
"signup": {
"type": "object",
"properties": {
"reward": {
"type": "object",
"properties": {
"productEnabled": {
"type": "boolean"
},
"productId": {
"anyOf": [
{
"type": "integer",
"minimum": 1
},
{
"type": "null"
}
]
},
"couponEnabled": {
"type": "boolean"
},
"offerId": {
"anyOf": [
{
"type": "integer",
"minimum": 1
},
{
"type": "null"
}
]
}
},
"additionalProperties": true
}
},
"additionalProperties": true
}
},
"additionalProperties": true
}
},
"additionalProperties": true,
"required": [
"revision",
"configuration"
]
}
HTTP 200 response (application/json)
{
"type": "object",
"properties": {
"configuration": {
"type": "object",
"properties": {
"productId": {
"type": "integer",
"minimum": 1
},
"enabled": {
"type": "boolean"
},
"showBeforeCheckout": {
"type": "boolean"
},
"heading": {
"type": "string",
"maxLength": 100
},
"body": {
"type": "string",
"maxLength": 400
},
"continueLabel": {
"type": "string",
"maxLength": 40
},
"layout": {
"type": "string",
"enum": [
"grid",
"stacked",
"featured"
]
},
"offers": {
"type": "array",
"maxItems": 12,
"items": {
"type": "object",
"properties": {
"id": {
"type": "string",
"pattern": "^[A-Za-z0-9_-]+$",
"maxLength": 64
},
"productId": {
"type": "integer",
"minimum": 1
},
"heading": {
"type": "string",
"maxLength": 100
},
"body": {
"type": "string",
"maxLength": 240
},
"badge": {
"type": "string",
"maxLength": 32
},
"requiredProductIds": {
"type": "array",
"maxItems": 14,
"uniqueItems": true,
"items": {
"type": "integer",
"minimum": 1
}
}
},
"additionalProperties": true,
"required": [
"id",
"productId"
]
}
},
"signupEnabled": {
"type": "boolean"
},
"signup": {
"type": "object",
"properties": {
"reward": {
"type": "object",
"properties": {
"productEnabled": {
"type": "boolean"
},
"productId": {
"anyOf": [
{
"type": "integer",
"minimum": 1
},
{
"type": "null"
}
]
},
"couponEnabled": {
"type": "boolean"
},
"offerId": {
"anyOf": [
{
"type": "integer",
"minimum": 1
},
{
"type": "null"
}
]
}
},
"additionalProperties": true
}
},
"additionalProperties": true
}
},
"additionalProperties": true
},
"revision": {
"type": "integer",
"minimum": 0
}
},
"additionalProperties": true
}
Documented failures: 400, 401, 403, 404, 409, 500, 503.
Operation errors: MARKETING_WEBSITE_REQUIRED, PRODUCT_MARKETING_INVALID, STOREFRONT_EDIT_CONFLICT, PRE_PURCHASE_PRODUCT_UNAVAILABLE.
SoundSync
Complete the offer
SoundSync
Select compatible extras for this product
Product Marketing can replace the website default when its product is in the cart. This example keeps the required instrument and additional compatibility rules with the offer.
