API Reference · v1
The Pretty Product Options API
Programmatic access to templates, options, pricing, products, customer groups and saved configurations. Available on the Advanced plan.
Authentication
Generate a token in the app under Settings → API access (shown once; only its hash is stored). API access is available on the Advanced plan. Send the token on every request:
Authorization: Bearer cov_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx- • Base URL: your app host, e.g.
https://<app-host>/api/v1/… - • All requests and responses are JSON.
- • Rate limit: 120 requests/minute per shop —
429when exceeded. - • Errors:
{ "error": "…" }with400 / 401 / 402 / 404 / 405 / 422 / 429 / 500. - •
401= bad token or app uninstalled;402= plan no longer Advanced. - • Regenerating or revoking the token invalidates the old one immediately.
Templates
Templates hold the option structure a product configurator renders: sections → options → choices, plus visibility rules and ruleset versions.
/api/v1/templatesList all templates.
Response
{ "templates": [{ "id": "…", "name": "Roller blinds", "product_config_id": null }] }- product_config_id set means a per-product option set; null means a shared template.
/api/v1/templatesCreate a template.
Request body
{ "name": "Roller blinds" }Response
201 { "ok": true, "id": "…" }/api/v1/templates/{id}Read the full tree: template, sections → options → choices, visibility rules, and the ruleset version list.
/api/v1/templates/{id}Update the structure declaratively.
Request body
{
"name": "Roller blinds",
"sections": [
{
"title": "Size",
"options": [
{ "key": "width", "label": "Width (cm)", "input_type": "number", "required": true, "default_value": "120" },
{ "key": "height", "label": "Height (cm)", "input_type": "number", "required": true, "default_value": "150" }
]
},
{
"title": "Fabric",
"options": [
{
"key": "fabric", "label": "Fabric", "input_type": "single_select",
"required": true, "display_mode": "swatch",
"choices": [
{ "label": "Blockout White", "value": "blockout_white", "swatch_color": "#f5f5f0" },
{ "label": "Sunscreen 5%", "value": "sunscreen_5", "price": 15 }
]
}
]
}
]
}- sections replaces the whole structure declaratively (options and choices get new ids).
- Visibility rules are cleared when sections is provided — pricing rules are unaffected because conditions reference stable option keys.
- Omit sections to rename only.
/api/v1/templates/{id}Remove the template and everything under it.
Pricing rulesets
Rulesets are versioned. Publishing replaces the live version the storefront prices with.
/api/v1/rulesets/{productConfigId}Read the live ruleset the storefront prices with: rules, validations, version and base price.
/api/v1/rulesets/{productConfigId}Replace the rules as a new version.
Request body
{
"rules": [
{ "kind": "adder", "config": { "label": "Base price", "amount": 89 } },
{ "kind": "raw_expression", "config": { "label": "Size", "expression": "(width/100)*(height/100)*65" } },
{
"kind": "multiplier", "config": { "label": "Motorised", "factor": 1.25 },
"applies_when": { "combinator": "and", "conditions": [{ "option_key": "control_type", "operator": "eq", "value": "motorised" }] }
}
],
"validations": [
{
"conditions": { "combinator": "or", "conditions": [{ "option_key": "width", "operator": "lt", "value": 30 }] },
"action": "block", "block_message": "Minimum width is 30 cm."
}
],
"publish": true
}- Creates a new draft version containing exactly these rules; bad rules fail compilation with 422.
- validations, when present, replaces the template's validation rules.
- publish: true makes it live immediately.
- Rule kinds: adder, multiplier, dimension_lookup, tier, raw_expression.
Price computation
Evaluate any configuration against the live ruleset — the same engine the storefront uses. No signature is issued; signed cart payloads only come from the storefront flow.
/api/v1/priceCompute a price for a configuration.
Request body
{
"product_config_id": "…",
"selections": { "fabric": "sunscreen_5", "control_type": "motorised" },
"dimensions": { "width": 120, "height": 150 }
}Response
{ "price": 262.13, "breakdown": { … }, "validation": { "ok": true }, "ruleset_version": 7 }- Batch: { "items": [ …same shape… ] } → { "results": […] }.
Draft orders & cart links
Programmatic assisted selling — the API twins of the in-app draft-order builder. Prices are always recomputed server-side from the live ruleset, and each line's configuration is persisted so orders reconcile normally.
/api/v1/draft-ordersCreate a Shopify draft order with configured lines — returns the invoice link.
Request body
{
"items": [
{
"product_config_id": "…",
"selections": { "fabric": "sunscreen_5" },
"dimensions": { "width": 120, "height": 150 },
"quantity": 2
}
],
"email": "customer@example.com"
}Response
{ "ok": true, "invoice_url": "…" }- Prices are locked at creation — the customer opens the link and pays.
- Items may use shopify_product_id instead of product_config_id.
- Validation blocks return 422 with the blocking message.
/api/v1/cart-linksSame items shape, editable vehicle: a link that rebuilds the items in the customer's cart.
Request body
{ "items": [ …same shape as draft-orders… ] }Response
{ "ok": true, "url": "https://your-store.com/cart?coverly_cart=…" }- Items are re-priced and re-signed when the link is opened — never stale.
- The customer can edit any line in their cart before checking out.
- Use draft orders for agreed quotes; cart links for editable proposals.
Products
/api/v1/productsList all configured products.
/api/v1/products/{shopifyProductId}Connect or update a product.
Request body
{ "anchor_variant_id": 45678901234, "template_id": "…", "base_config": { … }, "currency_mode": "auto_convert" }- base_config and currency_mode are optional.
/api/v1/products/{shopifyProductId}Disconnect the configurator from the product.
Customer groups
/api/v1/groupsList customer groups.
/api/v1/groupsCreate a group keyed to a customer tag.
Request body
{ "name": "Wholesale", "tag": "wholesale" }/api/v1/groups?id={uuid}Delete a group.
Saved configurations
The read model for ERP and manufacturing. Each row has uid (matches the order line's _config_id property), full selections, computed_price, price_breakdown, ruleset_version, lifecycle status (draft | saved | shared | carted | ordered | abandoned) and shopify_customer_id.
/api/v1/configs?status=ordered&since=2026-01-01T00:00:00Z&limit=100Query saved configurations by status and time window.
Typical ERP sync
POST /api/v1/templates, then build the structure withPUT /api/v1/templates/{id}PUT /api/v1/products/{productId}— connect a product to the templatePUT /api/v1/rulesets/{productConfigId}withpublish: true— price it- Nightly:
GET /api/v1/configs?status=ordered&since=…— pull specs into manufacturing; recompute spot checks withPOST /api/v1/price
