Made-to-measure blinds in South Africa: prices, stock, quotes, delivery times, window previews.
Maintain this server? Claim it
Call this server's tools from your browser. Nothing to install.
Requests go through mcptry because browsers can't call most MCP servers directly. Header values are sent to the server for that request only and are never stored or logged.
Tool list from our last check. Connect live to refresh it.
Permanently delete a cart by cart_id. Use when the customer abandons the session or wants to start over. Has no effect on any checkout or paid order already created from this cart. Irreversible, create a new cart to restart.
The server marks this tool as destructive. Running it may delete or overwrite data on the server or in any account you connected with your headers.
Pick your client. Values in capitals, like YOUR_TOKEN, are yours to fill in.
Run in a terminal
claude mcp add --transport http shop https://shop.customblinds.co.za/mcp
Permanently delete a cart by cart_id. Use when the customer abandons the session or wants to start over. Has no effect on any checkout or paid order already created from this cart. Irreversible, create a new cart to restart.
| Argument | Type | Description |
|---|---|---|
| cart_id* | string |
{
"type": "object",
"required": [
"cart_id"
],
"properties": {
"cart_id": {
"type": "string"
}
}
}Abort an unpaid checkout and release its checkout_id. Use if the customer changes their mind after create_checkout but before completing payment. Has no effect on orders already confirmed by webhook. To restart, create a new cart and checkout from scratch.
| Argument | Type | Description |
|---|---|---|
| checkout_id* | string |
{
"type": "object",
"required": [
"checkout_id"
],
"properties": {
"checkout_id": {
"type": "string"
}
}
}Verify whether a specific colour is available before configure_product. Returns in_stock boolean, expected_restock_date if out of stock, and up to 5 alternative in-stock colours ordered by similarity. Call this when a customer requests a named colour or when you want to prevent a configure_product failure due to an out-of-stock selection. Duo Roller: colour is one blockout and one sheer written "Blockout + Sheer" (get_product returns duo_fabrics).
| Argument | Type | Description |
|---|---|---|
| product_id* | string | |
| colour_name* | string |
{
"type": "object",
"required": [
"product_id",
"colour_name"
],
"properties": {
"product_id": {
"type": "string"
},
"colour_name": {
"type": "string"
}
}
}Generate a Yoco card or Ozow instant-EFT payment link; this does NOT complete payment. Rejects cancelled checkouts and rechecks stock and totals first. An atomic claim prevents competing gateway calls. Returns payment_url or null plus status and message; cloud callers may be held. Retain a successful URL: repeat calls return payment_pending with no URL. Gateway failures raise an error, send no payment-link email and require team review rather than an automatic retry. Poll get_order with customer_email for payment status.
| Argument | Type | Description |
|---|---|---|
| checkout_id* | string | |
| payment_method | string | Overrides any value set in create_checkout/update_checkout |
{
"type": "object",
"required": [
"checkout_id"
],
"properties": {
"checkout_id": {
"type": "string"
},
"payment_method": {
"enum": [
"yoco",
"ozow"
],
"type": "string",
"description": "Overrides any value set in create_checkout/update_checkout"
}
}
}Lock in a full blind specification: product, dimensions, colour, and mount type (inside recess or outside face-fix). Validates that the colour exists and is in stock, then prices the blind. Returns a configuration summary to pass directly into create_cart. Call check_colour_stock first if availability is uncertain. Duo Roller: colour is one blockout and one sheer written "Blockout + Sheer" (get_product returns duo_fabrics).
| Argument | Type | Description |
|---|---|---|
| colour* | string | Colour name (must match available colours) |
| finish | string | Optional finish for aluminium venetians |
| no_drill | boolean | Optional. true for the no-drill option (tension brackets, inside the frame, max 2000mm wide; 1500mm on 25mm venetians). Adds the R65 no-drill kit per blind. Offered on indoor roller blinds, including value rollers, and 25mm aluminium or aluwood venetians. Dedicated no-drill products already include the kit. |
| province | string | Optional. Customer's South African province or city. Garden Route locations get Duncan's direct contact; other locations get the online shop contact. |
| quantity | number | Number of blinds (default 1) |
| width_mm* | number | Width in millimetres |
Start the open UCP purchase flow, no auth needed. Creates a cart session and returns a cart_id (24-hour TTL). Optionally seed with pre-configured blind items and customer details. Next step: update_cart to add items, then create_checkout → complete_checkout to mint the payment link. Duo Roller: colour is one blockout and one sheer written "Blockout + Sheer" (get_product returns duo_fabrics).
| Argument | Type | Description |
|---|---|---|
| items | array | Optional configured items; all submitted prices are ignored |
| customer | object |
{
"type": "object",
"properties": {
"items": {
"type": "array",
"items": {
"type": "object",
"required": [
"product_id",
"width_mm",
"height_mm",
"colour",
"mount_type"
],
"properties": {
"colour": {
"type": "string",
"minLength": 1,
"description": "Exact available colour; validate with configure_product before adding"
},
"finish": {
"type": "string",
"description": "Optional pricing finish for aluminium Venetians"
},
"no_drill": {
"type": "boolean",
"description": "Optional. true for the no-drill option (tension brackets, inside the frame, max 2000mm wide; 1500mm on 25mm venetians). Adds the R65 no-drill kit per blind. Offered on indoor roller blinds, including value rollers, and 25mm aluminium or aluwood venetians. Dedicated no-drill products already include the kit."
},
"quantity": {
"type": "number",
"description": "Number of blinds; defaults to 1"
},
"width_mm": {
"type": "number",
"description": "Actual ordered width in millimetres",
"exclusiveMinimum": 0
},
"height_mm": {
"type": "number",
"description": "Actual ordered drop in millimetres",
"exclusiveMinimum": 0
},
"mount_type": {
"type": "string",
"minLength": 1,
"description": "Use inside for inside mount or outside for face fix"
},
"product_id": {
"type": "string",
"description": "product_id returned by search_catalog or lookup_catalog"
},
"product_name": {
"type": "string",
"description": "Optional; server resolves the catalogue name"
},
"unit_price_zar": {
"type": "number",
"description": "Optional, ignored: server recalculates all prices"
},
"total_price_zar": {
"type": "number",
"description": "Optional, ignored: server recalculates all totals"
}
}
},
"description": "Optional configured items; all submitted prices are ignored"
},
"customer": {
"type": "object",
"properties": {
"city": {
"type": "string"
},
"name": {
"type": "string",
"description": "Real customer name, checked before checkout creation"
},
"email": {
"type": "string",
"description": "Real customer email, checked before checkout creation"
},
"phone": {
"type": "string",
"description": "South African phone number, checked before checkout creation"
},
"address": {
"type": "string"
}
}
}
}
}Phase 1 of 2 in the purchase flow. Convert a cart (or inline items + customer) into a checkout. Customer name, email, and phone are required. Returns checkout_id. No payment link is minted yet, call complete_checkout for that. Use update_checkout to correct customer details before finalising.
| Argument | Type | Description |
|---|---|---|
| items | array | |
| cart_id | string | Either cart_id or items required |
| customer | object | |
| payment_method | string | Default 'yoco' |
{
"type": "object",
"anyOf": [
{
"required": [
"cart_id"
]
},
{
"required": [
"items",
"customer"
],
"properties": {
"customer": {
"required": [
"name",
"email",
"phone"
]
}
}
}
],
"properties": {
"items": {
"type": "array",
"items": {
"type": "object",
"required": [
"product_id",
"width_mm",
"height_mm",
"colour",
"mount_type"
],
"properties": {
"colour": {
"type": "string",
"minLength": 1,
"description": "Exact available colour; validate with configure_product before adding"
},
"finish": {
"type": "string",
"description": "Optional pricing finish for aluminium Venetians"
},
"no_drill": {
"type": "boolean",
"description": "Optional. true for the no-drill option (tension brackets, inside the frame, max 2000mm wide; 1500mm on 25mm venetians). Adds the R65 no-drill kit per blind. Offered on indoor roller blinds, including value rollers, and 25mm aluminium or aluwood venetians. Dedicated no-drill products already include the kit."
},
"quantity": {
"type": "number",
"description": "Number of blinds; defaults to 1"
},
"width_mm": {
"type": "number",
"description": "Actual ordered width in millimetres",
"exclusiveMinimum": 0
},
"height_mm": {
"type": "number",
"description": "Actual ordered drop in millimetres",
"exclusiveMinimum": 0
},
"mount_type": {
"type": "string",
"minLength": 1,
"description": "Use inside for inside mount or outside for face fix"
},
"product_id": {
"type": "string",
"description": "product_id returned by search_catalog or lookup_catalog"
},
"product_name": {
"type": "string",
"description": "Optional; server resolves the catalogue name"
},
"unit_price_zar": {
"type": "number",
"description": "Optional, ignored: server recalculates all prices"
},
"total_price_zar": {
"type": "number",
"description": "Optional, ignored: server recalculates all totals"
}
}
},
"minItems": 1
},
"cart_id": {
"type": "string",
"description": "Either cart_id or items required"
},
"customer": {
"type": "object",
"properties": {
"city": {
"type": "string"
},
"name": {
"type": "string",
"description": "Real customer name, checked before checkout creation"
},
"email": {
"type": "string",
"description": "Real customer email, checked before checkout creation"
},
"phone": {
"type": "string",
"description": "South African phone number, checked before checkout creation"
},
"address": {
"type": "string"
}
}
},
"payment_method": {
"enum": [
"yoco",
"ozow"
],
"type": "string",
"description": "Default 'yoco'"
}
}
}Make a shareable quote page for the customer, with no side effects: no order, no email, no payment link and no stock hold. Each blind is priced and stock-checked now; the page shows the lines and total and its button fills the customer's cart and opens checkout, where prices are checked again. Valid 7 days. Use this when the customer wants to review, share or pay later, instead of create_checkout.
| Argument | Type | Description |
|---|---|---|
| items* | array | Configured blinds; validate colours with configure_product first |
{
"type": "object",
"required": [
"items"
],
"properties": {
"items": {
"type": "array",
"items": {
"type": "object",
"required": [
"product_id",
"width_mm",
"height_mm",
"colour",
"mount_type"
],
"properties": {
"colour": {
"type": "string",
"minLength": 1,
"description": "Exact available colour; validate with configure_product before adding"
},
"finish": {
"type": "string",
"description": "Optional pricing finish for aluminium Venetians"
},
"no_drill": {
"type": "boolean",
"description": "Optional. true for the no-drill option (tension brackets, inside the frame, max 2000mm wide; 1500mm on 25mm venetians). Adds the R65 no-drill kit per blind. Offered on indoor roller blinds, including value rollers, and 25mm aluminium or aluwood venetians. Dedicated no-drill products already include the kit."
},
"quantity": {
"type": "number",
"description": "Number of blinds; defaults to 1"
},
"width_mm": {
"type": "number",
"description": "Actual ordered width in millimetres",
"exclusiveMinimum": 0
},
"height_mm": {
"type": "number",
"description": "Actual ordered drop in millimetres",
"exclusiveMinimum": 0
},
"mount_type": {
"type": "string",
"minLength": 1,
"description": "Use inside for inside mount or outside for face fix"
},
"product_id": {
"type": "string",
"description": "product_id returned by search_catalog or lookup_catalog"
},
"control_side": {
"enum": [
"left",
"right"
],
"type": "string",
"description": "Chain or control side, as the customer faces the window. Defaults to right."
},
"product_name": {
"type": "string",
"description": "Optional; server resolves the catalogue name"
},
"unit_price_zar": {
"type": "number",
"description": "Optional, ignored: server recalculates all prices"
},
"total_price_zar": {
"type": "number",
"description": "Optional, ignored: server recalculates all totals"
}
}
},
"maxItems": 20,
"minItems": 1,
"description": "Configured blinds; validate colours with configure_product first"
}
}
}Returns the link to the Custom Blinds Visualiser (See it before you buy it), pre-selected to the product when it is supported. The customer adds a photo of their window (any angle), picks a blind and colour, and previews it on their own window. A preview of colour and style, not a measuring tool. No measuring or marking. A name and WhatsApp number are needed; 2 free previews per customer. Also returns the measuring guide (mode 'measure' makes it the main url) and the list of supported products. A customer still unsure of sizes can order with best guess sizes, receive a free tape measure and confirm before production starts. Use when a customer wants to see how a blind or colour will look before ordering, or is unsure how to measure. If you already have the customer's photo, use start_visualiser_preview to show the blind in this chat instead.
| Argument | Type | Description |
|---|---|---|
| mode | string | Which link goes in url: visualize (own-window visualiser), measure (measuring guide) or both (visualiser, the default). Both links are always returned. |
| product_id | string | Optional. Pre-select a product in the visualiser (e.g. roller-blockout, double-roller-zebra, outdoor-blinds). |
{
"type": "object",
"properties": {
"mode": {
"enum": [
"measure",
"visualize",
"both"
],
"type": "string",
"description": "Which link goes in url: visualize (own-window visualiser), measure (measuring guide) or both (visualiser, the default). Both links are always returned."
},
"product_id": {
"type": "string",
"description": "Optional. Pre-select a product in the visualiser (e.g. roller-blockout, double-roller-zebra, outdoor-blinds)."
}
}
}Retrieve live cart state by cart_id: full item list, calculated totals in ZAR, and any customer details stored so far. Call after update_cart to confirm changes are correct before proceeding to create_checkout. Cart expires after 24 hours of inactivity.
| Argument | Type | Description |
|---|---|---|
| cart_id* | string |
{
"type": "object",
"required": [
"cart_id"
],
"properties": {
"cart_id": {
"type": "string"
}
}
}Read checkout by checkout_id. Returns persisted order status, payment_status, payment_method, items, customer, total_zar and currency. Initial order status is started, not pending. This tool does not return a previously generated payment_url: retain the complete_checkout response in caller context.
| Argument | Type | Description |
|---|---|---|
| checkout_id* | string |
{
"type": "object",
"required": [
"checkout_id"
],
"properties": {
"checkout_id": {
"type": "string"
}
}
}Lead time for a new order. Production takes 5 to 7 working days once payment clears, outside peak seasons. Pass the customer's town and 4-digit street postal_code (province and suburb help) and the transit range is The Courier Guy's own quote from our Knysna depot to that town; without them it is the standard 2 to 5 working days. Returns working-day ranges and a summary safe to share. Never quote a dispatch or delivery date: weather and production set them.
| Argument | Type | Description |
|---|---|---|
| town | string | Customer's town or city, e.g. 'Johannesburg' |
| suburb | string | Optional suburb, e.g. Sandton |
| province | string | Optional province, e.g. Gauteng |
| width_mm | number | Optional widest blind in mm (sets the parcel length) |
| order_date | string | ISO date of the order (e.g. '2026-05-18'). Defaults to today. |
| postal_code | string | 4-digit South African STREET postal code, e.g. 2196 |
{
"type": "object",
"properties": {
"town": {
"type": "string",
"description": "Customer's town or city, e.g. 'Johannesburg'"
},
"suburb": {
"type": "string",
"description": "Optional suburb, e.g. Sandton"
},
"province": {
"type": "string",
"description": "Optional province, e.g. Gauteng"
},
"width_mm": {
"type": "number",
"description": "Optional widest blind in mm (sets the parcel length)"
},
"order_date": {
"type": "string",
"description": "ISO date of the order (e.g. '2026-05-18'). Defaults to today."
},
"postal_code": {
"type": "string",
"description": "4-digit South African STREET postal code, e.g. 2196"
}
}
}Retrieve a confirmed order's status, items, and payment details by order_id. customer_email is required as soft-auth and must exactly match the order record, prevents arbitrary order lookups. Returns payment status (paid | pending | failed), production status, and dispatch date once available.
| Argument | Type | Description |
|---|---|---|
| order_id* | string | |
| customer_email* | string |
{
"type": "object",
"required": [
"order_id",
"customer_email"
],
"properties": {
"order_id": {
"type": "string"
},
"customer_email": {
"type": "string"
}
}
}List available payment processors and their capabilities. Returns Yoco (card, immediate) and Ozow (instant EFT via South African bank account). Call when the customer asks 'how can I pay?' or before presenting options. The result informs the payment_method field in create_checkout and complete_checkout.
| Argument | Type | Description |
|---|---|---|
| order_total_zar | number | Optional. For future per-handler limit filtering. |
{
"type": "object",
"properties": {
"order_total_zar": {
"type": "number",
"description": "Optional. For future per-handler limit filtering."
}
}
}Get an exact ZAR price using product_id from search_catalog or lookup_catalog, width_mm and height_mm. Prices include VAT and delivery. Colour selects the bamboo price tier where applicable. A price is not a stock reservation: validate the exact colour and mount with configure_product before creating a cart. Failure can return success:false or a JSON-RPC validation error.
| Argument | Type | Description |
|---|---|---|
| colour | string | Optional bamboo colour for colour-specific tier pricing |
| finish | string | Optional finish for aluminium products: Plain, Brushed, Woodgrain |
| no_drill | boolean | Optional. true for the no-drill option (tension brackets, inside the frame, max 2000mm wide; 1500mm on 25mm venetians). Adds the R65 no-drill kit per blind. Offered on indoor roller blinds, including value rollers, and 25mm aluminium or aluwood venetians. Dedicated no-drill products already include the kit. |
| province | string | Optional. Customer's South African province or city. Garden Route locations get Duncan's direct contact; other locations get the online shop contact. |
| quantity | number | Number of blinds (default 1) |
| width_mm* | number | Width in millimetres (e.g. 1200) |
| height_mm |
Fetch complete details for one product by id (e.g. roller-blockout, venetian-25mm-aluwood). Returns all available colours with in-stock status, materials, features, and maximum supported dimensions. Use before configure_product to confirm a colour exists and is in stock before committing. Duo Roller: colour is one blockout and one sheer written "Blockout + Sheer" (get_product returns duo_fabrics).
| Argument | Type | Description |
|---|---|---|
| product_id* | string |
{
"type": "object",
"required": [
"product_id"
],
"properties": {
"product_id": {
"type": "string"
}
}
}Translate a customer's primary concern into a product recommendation. primary_concern must be one of: blockout, heat, glare, moisture, privacy, security, automation. Optionally narrow by room (bedroom, lounge, etc.), location, budget, and aesthetic. Returns a recommended product_id with rationale, pass it to get_price or configure_product next. For security there is no shop product: it returns a hand-off to our security shutters page (installed in the Garden Route only).
| Argument | Type | Description |
|---|---|---|
| room | string | |
| location | string | |
| aesthetic | string | |
| max_budget_zar | number | |
| primary_concern* | string |
{
"type": "object",
"required": [
"primary_concern"
],
"properties": {
"room": {
"type": "string"
},
"location": {
"type": "string"
},
"aesthetic": {
"type": "string"
},
"max_budget_zar": {
"type": "number"
},
"primary_concern": {
"enum": [
"blockout",
"heat",
"glare",
"moisture",
"privacy",
"security",
"automation"
],
"type": "string"
}
}
}Draw and return the preview for a job_id from start_visualiser_preview: the blind in the chosen colour on the customer's photo, as an image in the result and as image_url (kept 7 days). The first call draws it (30 to 90 s; outdoor up to 2 minutes); status "drawing" means call again after retry_after_seconds.
| Argument | Type | Description |
|---|---|---|
| job_id* | string |
{
"type": "object",
"required": [
"job_id"
],
"properties": {
"job_id": {
"type": "string"
}
}
}Generate a pre-filled WhatsApp deep link to hand the customer off to the right contact. Garden Route locations (Knysna, Plett, George, Sedgefield, etc.) route to Duncan Kane on WhatsApp (+27795235407) for a free in-home consultation; all other South African locations route to the shop WhatsApp (+27760228410), WhatsApp only, no voice calls. Use when the customer prefers human assistance or when self-serve checkout isn't appropriate.
| Argument | Type | Description |
|---|---|---|
| message | string | Optional additional message to prefill |
| location | string | City/suburb. Drives Duncan vs shop routing. |
| customer_name | string | |
| product_context | string | e.g. 'roller blockout for bedroom' |
{
"type": "object",
"properties": {
"message": {
"type": "string",
"description": "Optional additional message to prefill"
},
"location": {
"type": "string",
"description": "City/suburb. Drives Duncan vs shop routing."
},
"customer_name": {
"type": "string"
},
"product_context": {
"type": "string",
"description": "e.g. 'roller blockout for bedroom'"
}
}
}Preferred structured discovery. Filter by category, partial colour name or required supported width/drop in mm. Returns results containing product_id, name, category and product_url, plus total. Width/drop filters check separate maximums, not every combination; confirm the exact pair with get_price.
| Argument | Type | Description |
|---|---|---|
| colour | string | |
| category | string | roller | venetian | honeycomb | vertical | outdoor |
| max_width_mm | number | |
| max_height_mm | number |
{
"type": "object",
"properties": {
"colour": {
"type": "string"
},
"category": {
"type": "string",
"description": "roller | venetian | honeycomb | vertical | outdoor"
},
"max_width_mm": {
"type": "number"
},
"max_height_mm": {
"type": "number"
}
}
}Submit a price match claim when the customer has found the same blind at a lower price elsewhere. Custom Blinds matches verified South African retailer prices for identical product, dimensions, and specs. Returns a pre-filled WhatsApp link to the claims team. Not applicable to clearance or flash-sale prices, international retailers, or items out of stock at the other retailer. Requires product_id and competitor_price_zar at minimum.
| Argument | Type | Description |
|---|---|---|
| width_mm | number | Window width in mm |
| height_mm | number | Window height/drop in mm |
| product_id* | string | Product the customer wants to match (e.g. roller-blockout) |
| customer_name | string | Customer name |
| competitor_url | string | URL to competitor product page or quote |
| competitor_name | string | Name of the other retailer |
| customer_whatsapp | string | Customer WhatsApp number for follow-up |
| competitor_price_zar* |
Log up to 5 colour codes against an EXISTING order for the team (order_ref required; without it the tool returns status order_required and logs nothing). Sample swatches, not off-cuts: on orders over R8,000 the customer can ask on WhatsApp for swatches in the colours they like, for the product they are ordering; if nothing suits, full refund with no fees. Never quote a sample price or courier cost.
| Argument | Type | Description |
|---|---|---|
| suburb | string | Optional delivery suburb |
| order_ref* | string | The order reference the swatches ship with. Required. |
| swatch_codes | array | Optional specific colour codes (max 5) |
| customer_name* | string | Customer's full name. |
| customer_email* | string | Customer's email address. |
| customer_phone* | string | Used as WhatsApp number |
| product_interest* | string | e.g. 'Roller Blockout' or 'Honeycomb' |
{
"type": "object",
"required": [
"customer_name",
"customer_email",
"customer_phone",
"product_interest",
"order_ref"
],
"properties": {
"suburb": {
"type": "string",
"description": "Optional delivery suburb"
},
"order_ref": {
"type": "string",
"description": "The order reference the swatches ship with. Required."
},
"swatch_codes": {
"type": "array",
"items": {
"type": "string"
},
"description": "Optional specific colour codes (max 5)"
},
"customer_name": {
"type": "string",
"description": "Customer's full name."
},
"customer_email": {
"type": "string",
"description": "Customer's email address."
},
"customer_phone": {
"type": "string",
"description": "Used as WhatsApp number"
},
"product_interest": {
"type": "string",
"description": "e.g. 'Roller Blockout' or 'Honeycomb'"
}
}
}Preferred free-text discovery. Returns results containing product_id, name, category, description, product_url and colour_count_in_stock, plus total and currency. For structured filters use lookup_catalog. Pass product_id to get_product or get_price.
| Argument | Type | Description |
|---|---|---|
| query | string | Free-text query, e.g. 'blockout' or 'venetian' |
{
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "Free-text query, e.g. 'blockout' or 'venetian'"
}
}
}Show the customer a blind on THEIR OWN window or patio, in this chat. Pass the photo they gave you (image_url https, or image_base64; for outdoor blinds, the patio opening taken straight on), the product_id and an exact in-stock colour name (get_product), and the customer's name and South African WhatsApp number (required: the team follows up on WhatsApp, and each number gets 2 free previews). Indoor blinds, and the outdoor screen, clear PVC and canvas blinds (not outdoor bamboo). Finds the windows or patio openings (20 to 45 s) and returns job_id; then call get_visualiser_preview. A preview of colour and style, not a measuring tool.
| Argument | Type | Description |
|---|---|---|
| colour* | string | Exact in-stock colour name from get_product (for a Duo Roller, one of its listed colours) |
| whatsapp* | string | Customer's South African WhatsApp number |
| image_url | string | https URL of the customer's window or patio photo (JPEG, PNG or WebP, under 6 MB) |
| product_id* | string | Visualiser blind, e.g. roller-blockout, duo-roller, venetian-25mm-aluminium, honeycomb-blockout, outdoor-blinds, outdoor-blinds-pvc, outdoor-blinds-canvas |
| image_base64 | string | Or the photo itself, base64 |
| customer_name* | string |
Modify an open cart before checkout. op: 'add' appends items, 'remove' drops items by 0-based index, 'set' replaces the full item list, 'clear' empties the cart. Merges customer details (name, email, phone) via the customer field. Call get_cart afterwards to confirm. Cannot modify a cart that already has a checkout in progress.
| Argument | Type | Description |
|---|---|---|
| op | string | |
| items | array | |
| cart_id* | string | |
| indices | array | Item indices to remove (0-based) when op='remove' |
| customer | object |
{
"type": "object",
"required": [
"cart_id"
],
"properties": {
"op": {
"enum": [
"add",
"remove",
"set",
"clear"
],
"type": "string",
"default": "set"
},
"items": {
"type": "array",
"items": {
"type": "object",
"required": [
"product_id",
"width_mm",
"height_mm",
"colour",
"mount_type"
],
"properties": {
"colour": {
"type": "string",
"minLength": 1,
"description": "Exact available colour; validate with configure_product before adding"
},
"finish": {
"type": "string",
"description": "Optional pricing finish for aluminium Venetians"
},
"no_drill": {
"type": "boolean",
"description": "Optional. true for the no-drill option (tension brackets, inside the frame, max 2000mm wide; 1500mm on 25mm venetians). Adds the R65 no-drill kit per blind. Offered on indoor roller blinds, including value rollers, and 25mm aluminium or aluwood venetians. Dedicated no-drill products already include the kit."
},
"quantity": {
"type": "number",
"description": "Number of blinds; defaults to 1"
},
"width_mm": {
"type": "number",
"description": "Actual ordered width in millimetres",
"exclusiveMinimum": 0
},
"height_mm": {
"type": "number",
"description": "Actual ordered drop in millimetres",
"exclusiveMinimum": 0
},
"mount_type": {
"type": "string",
"minLength": 1,
"description": "Use inside for inside mount or outside for face fix"
},
"product_id": {
"type": "string",
"description": "product_id returned by search_catalog or lookup_catalog"
},
"product_name": {
"type": "string",
"description": "Optional; server resolves the catalogue name"
},
"unit_price_zar": {
"type": "number",
"description": "Optional, ignored: server recalculates all prices"
},
"total_price_zar": {
"type": "number",
"description": "Optional, ignored: server recalculates all totals"
}
}
}
},
"cart_id": {
"type": "string"
},
"indices": {
"type": "array",
"items": {
"type": "number"
},
"description": "Item indices to remove (0-based) when op='remove'"
},
"customer": {
"type": "object",
"properties": {
"city": {
"type": "string"
},
"name": {
"type": "string",
"description": "Real customer name, checked before checkout creation"
},
"email": {
"type": "string",
"description": "Real customer email, checked before checkout creation"
},
"phone": {
"type": "string",
"description": "South African phone number, checked before checkout creation"
},
"address": {
"type": "string"
}
}
}
}
}Update customer details or payment_method only before payment-link generation. Paid, cancelled and payment-in-progress checkouts are rejected. Concurrent state changes are detected; retrieve the latest status before retrying.
| Argument | Type | Description |
|---|---|---|
| customer | object | |
| checkout_id* | string | |
| payment_method | string |
{
"type": "object",
"required": [
"checkout_id"
],
"properties": {
"customer": {
"type": "object",
"properties": {
"city": {
"type": "string"
},
"name": {
"type": "string",
"description": "Real customer name, checked before checkout creation"
},
"email": {
"type": "string",
"description": "Real customer email, checked before checkout creation"
},
"phone": {
"type": "string",
"description": "South African phone number, checked before checkout creation"
},
"address": {
"type": "string"
}
}
},
"checkout_id": {
"type": "string"
},
"payment_method": {
"enum": [
"yoco",
"ozow"
],
"type": "string"
}
}
}Check a customer's sizes before pricing. Returns ok, problems (must fix), warnings (ask the customer) and advice: size limits for the product, product minimums, centimetre slips, inside-mount reveal depth (single rollers 50mm, no-drill rollers included; Double Roller zebra 90mm; Duo Roller 100mm), no-drill rules (inside only, at least 50mm reveal on rollers and 40mm on 25mm venetians, 2000mm max width, 1500mm on 25mm venetians), face-fix sizing (add 100mm each side and 100mm above and below) and the width we deduct when making an inside mount. Changes nothing and returns no price.
| Argument | Type | Description |
|---|---|---|
| colour | string | Optional exact colour name, checked for stock and width limits |
| no_drill | boolean | Optional. true for the no-drill option (tension brackets, inside the frame, max 2000mm wide; 1500mm on 25mm venetians). Adds the R65 no-drill kit per blind. Offered on indoor roller blinds, including value rollers, and 25mm aluminium or aluwood venetians. Dedicated no-drill products already include the kit. |
| width_mm* | number | Width the customer will enter, in millimetres |
| height_mm* | number | Drop the customer will enter, in millimetres |
| mount_type | string | inside (in the recess) or outside (face fix) |
| product_id |
We read every tool's name, description and inputs the way the model will, looking for instructions hidden from you. A clean result means no warning signs, not a guarantee. Scanned Nov 15, 2026.
| height_mm* |
| number |
| Height/drop in millimetres |
| mount_type* | string | Use inside (recess) or outside (face-fix); handler requires a nonempty value |
| product_id* | string | product_id from search_catalog or lookup_catalog |
{
"type": "object",
"required": [
"product_id",
"width_mm",
"height_mm",
"colour",
"mount_type"
],
"properties": {
"colour": {
"type": "string",
"description": "Colour name (must match available colours)"
},
"finish": {
"type": "string",
"description": "Optional finish for aluminium venetians"
},
"no_drill": {
"type": "boolean",
"description": "Optional. true for the no-drill option (tension brackets, inside the frame, max 2000mm wide; 1500mm on 25mm venetians). Adds the R65 no-drill kit per blind. Offered on indoor roller blinds, including value rollers, and 25mm aluminium or aluwood venetians. Dedicated no-drill products already include the kit."
},
"province": {
"type": "string",
"description": "Optional. Customer's South African province or city. Garden Route locations get Duncan's direct contact; other locations get the online shop contact."
},
"quantity": {
"type": "number",
"description": "Number of blinds (default 1)"
},
"width_mm": {
"type": "number",
"description": "Width in millimetres"
},
"height_mm": {
"type": "number",
"description": "Height/drop in millimetres"
},
"mount_type": {
"type": "string",
"minLength": 1,
"description": "Use inside (recess) or outside (face-fix); handler requires a nonempty value"
},
"product_id": {
"type": "string",
"description": "product_id from search_catalog or lookup_catalog"
}
}
}| number |
| Height/drop in millimetres (e.g. 1500) |
| product_id* | string | product_id from search_catalog or lookup_catalog (e.g. roller-blockout) |
{
"type": "object",
"required": [
"product_id",
"width_mm",
"height_mm"
],
"properties": {
"colour": {
"type": "string",
"description": "Optional bamboo colour for colour-specific tier pricing"
},
"finish": {
"type": "string",
"description": "Optional finish for aluminium products: Plain, Brushed, Woodgrain"
},
"no_drill": {
"type": "boolean",
"description": "Optional. true for the no-drill option (tension brackets, inside the frame, max 2000mm wide; 1500mm on 25mm venetians). Adds the R65 no-drill kit per blind. Offered on indoor roller blinds, including value rollers, and 25mm aluminium or aluwood venetians. Dedicated no-drill products already include the kit."
},
"province": {
"type": "string",
"description": "Optional. Customer's South African province or city. Garden Route locations get Duncan's direct contact; other locations get the online shop contact."
},
"quantity": {
"type": "number",
"description": "Number of blinds (default 1)"
},
"width_mm": {
"type": "number",
"description": "Width in millimetres (e.g. 1200)"
},
"height_mm": {
"type": "number",
"description": "Height/drop in millimetres (e.g. 1500)"
},
"product_id": {
"type": "string",
"description": "product_id from search_catalog or lookup_catalog (e.g. roller-blockout)"
}
}
}| number |
| Competitor's price in ZAR (incl. VAT) |
{
"type": "object",
"required": [
"product_id",
"competitor_price_zar"
],
"properties": {
"width_mm": {
"type": "number",
"description": "Window width in mm"
},
"height_mm": {
"type": "number",
"description": "Window height/drop in mm"
},
"product_id": {
"type": "string",
"description": "Product the customer wants to match (e.g. roller-blockout)"
},
"customer_name": {
"type": "string",
"description": "Customer name"
},
"competitor_url": {
"type": "string",
"description": "URL to competitor product page or quote"
},
"competitor_name": {
"type": "string",
"description": "Name of the other retailer"
},
"customer_whatsapp": {
"type": "string",
"description": "Customer WhatsApp number for follow-up"
},
"competitor_price_zar": {
"type": "number",
"description": "Competitor's price in ZAR (incl. VAT)"
}
}
}{
"type": "object",
"required": [
"product_id",
"colour",
"customer_name",
"whatsapp"
],
"properties": {
"colour": {
"type": "string",
"description": "Exact in-stock colour name from get_product (for a Duo Roller, one of its listed colours)"
},
"whatsapp": {
"type": "string",
"description": "Customer's South African WhatsApp number"
},
"image_url": {
"type": "string",
"description": "https URL of the customer's window or patio photo (JPEG, PNG or WebP, under 6 MB)"
},
"product_id": {
"type": "string",
"description": "Visualiser blind, e.g. roller-blockout, duo-roller, venetian-25mm-aluminium, honeycomb-blockout, outdoor-blinds, outdoor-blinds-pvc, outdoor-blinds-canvas"
},
"image_base64": {
"type": "string",
"description": "Or the photo itself, base64"
},
"customer_name": {
"type": "string"
}
}
}| string |
| product_id from search_catalog or lookup_catalog |
| opening_drop_mm | number | Optional, face fix only: drop of the opening itself |
| reveal_depth_mm | number | Optional depth of the recess in mm, needed for inside mounts and no-drill |
| opening_width_mm | number | Optional, face fix only: width of the opening itself |
{
"type": "object",
"required": [
"product_id",
"width_mm",
"height_mm"
],
"properties": {
"colour": {
"type": "string",
"description": "Optional exact colour name, checked for stock and width limits"
},
"no_drill": {
"type": "boolean",
"description": "Optional. true for the no-drill option (tension brackets, inside the frame, max 2000mm wide; 1500mm on 25mm venetians). Adds the R65 no-drill kit per blind. Offered on indoor roller blinds, including value rollers, and 25mm aluminium or aluwood venetians. Dedicated no-drill products already include the kit."
},
"width_mm": {
"type": "number",
"description": "Width the customer will enter, in millimetres"
},
"height_mm": {
"type": "number",
"description": "Drop the customer will enter, in millimetres"
},
"mount_type": {
"type": "string",
"description": "inside (in the recess) or outside (face fix)"
},
"product_id": {
"type": "string",
"description": "product_id from search_catalog or lookup_catalog"
},
"opening_drop_mm": {
"type": "number",
"description": "Optional, face fix only: drop of the opening itself"
},
"reveal_depth_mm": {
"type": "number",
"description": "Optional depth of the recess in mm, needed for inside mounts and no-drill"
},
"opening_width_mm": {
"type": "number",
"description": "Optional, face fix only: width of the opening itself"
}
}
}