Appearance
storefront
17 endpoints.
GET /api/v1/storefront/items
List Items By Sku
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
skus | query | yes | string | Comma-separated item codes/SKUs |
200 — Successful Response
json
{
"type": "array",
"items": {
"properties": {
"sku": {
"type": "string",
"title": "Sku"
},
"name": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Name"
},
"uom": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Uom"
},
"is_sales": {
"type": "boolean",
"title": "Is Sales"
},
"is_stock_item": {
"type": "boolean",
"title": "Is Stock Item"
},
"disabled": {
"type": "boolean",
"title": "Disabled"
}
},
"type": "object",
"required": [
"sku",
"name",
"uom",
"is_sales",
"is_stock_item",
"disabled"
],
"title": "StorefrontItem"
},
"title": "Response List Items By Sku Api V1 Storefront Items Get"
}422 — Validation Error
json
{
"properties": {
"detail": {
"items": {
"properties": {
"loc": {
"items": {
"anyOf": [
{
"type": "string"
},
{
"type": "integer"
}
]
},
"type": "array",
"title": "Location"
},
"msg": {
"type": "string",
"title": "Message"
},
"type": {
"type": "string",
"title": "Error Type"
}
},
"type": "object",
"required": [
"loc",
"msg",
"type"
],
"title": "ValidationError"
},
"type": "array",
"title": "Detail"
}
},
"type": "object",
"title": "HTTPValidationError"
}GET /api/v1/storefront/item-prices
List Item Prices
General list pricing only (customer_id IS NULL) — not customer-specific negotiated rates.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
skus | query | yes | string | Comma-separated item codes/SKUs |
price_list | query | no | Price list name; omit for all enabled selling price lists |
200 — Successful Response
json
{
"type": "array",
"items": {
"properties": {
"sku": {
"type": "string",
"title": "Sku"
},
"price_list": {
"type": "string",
"title": "Price List"
},
"currency": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Currency"
},
"rate": {
"type": "number",
"title": "Rate"
},
"rate_gbp": {
"anyOf": [
{
"type": "number"
},
{
"type": "null"
}
],
"title": "Rate Gbp"
},
"min_qty": {
"type": "number",
"title": "Min Qty"
}
},
"type": "object",
"required": [
"sku",
"price_list",
"currency",
"rate",
"rate_gbp",
"min_qty"
],
"title": "StorefrontItemPrice"
},
"title": "Response List Item Prices Api V1 Storefront Item Prices Get"
}422 — Validation Error
json
{
"properties": {
"detail": {
"items": {
"properties": {
"loc": {
"items": {
"anyOf": [
{
"type": "string"
},
{
"type": "integer"
}
]
},
"type": "array",
"title": "Location"
},
"msg": {
"type": "string",
"title": "Message"
},
"type": {
"type": "string",
"title": "Error Type"
}
},
"type": "object",
"required": [
"loc",
"msg",
"type"
],
"title": "ValidationError"
},
"type": "array",
"title": "Detail"
}
},
"type": "object",
"title": "HTTPValidationError"
}GET /api/v1/storefront/customers
Find Customer By Email
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
email | query | yes | string | Exact email match (case-insensitive) |
200 — Successful Response
json
{
"type": "array",
"items": {
"properties": {
"id": {
"type": "string",
"title": "Id"
},
"name": {
"type": "string",
"title": "Name"
},
"email": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Email"
},
"phone": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Phone"
},
"currency": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Currency"
},
"disabled": {
"type": "boolean",
"title": "Disabled"
},
"customer_group": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Customer Group"
},
"default_price_list": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Default Price List"
}
},
"type": "object",
"required": [
"id",
"name",
"email",
"phone",
"currency",
"disabled",
"customer_group",
"default_price_list"
],
"title": "StorefrontCustomer"
},
"title": "Response Find Customer By Email Api V1 Storefront Customers Get"
}422 — Validation Error
json
{
"properties": {
"detail": {
"items": {
"properties": {
"loc": {
"items": {
"anyOf": [
{
"type": "string"
},
{
"type": "integer"
}
]
},
"type": "array",
"title": "Location"
},
"msg": {
"type": "string",
"title": "Message"
},
"type": {
"type": "string",
"title": "Error Type"
}
},
"type": "object",
"required": [
"loc",
"msg",
"type"
],
"title": "ValidationError"
},
"type": "array",
"title": "Detail"
}
},
"type": "object",
"title": "HTTPValidationError"
}POST /api/v1/storefront/customers
Create Storefront Customer
Create a brand-new Customer for a first-time storefront checkout. No generic /accounting/documents/{doctype} equivalent exists — Customer was never one of the doctypes that endpoint supports (see accounting_documents._ITEM_DOCS) — so this is a small, purpose-built create, same spirit as the rest of this module. Group/territory are resolved by name if a row with that name exists; left unset otherwise (both nullable) rather than failing the whole checkout over it.
Request body
json
{
"properties": {
"name": {
"type": "string",
"title": "Name"
},
"email": {
"type": "string",
"title": "Email"
},
"phone": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Phone"
}
},
"type": "object",
"required": [
"name",
"email"
],
"title": "StorefrontCustomerIn"
}201 — Successful Response
json
{
"properties": {
"id": {
"type": "string",
"title": "Id"
},
"name": {
"type": "string",
"title": "Name"
},
"email": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Email"
},
"phone": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Phone"
},
"currency": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Currency"
},
"disabled": {
"type": "boolean",
"title": "Disabled"
},
"customer_group": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Customer Group"
},
"default_price_list": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Default Price List"
}
},
"type": "object",
"required": [
"id",
"name",
"email",
"phone",
"currency",
"disabled",
"customer_group",
"default_price_list"
],
"title": "StorefrontCustomer"
}422 — Validation Error
json
{
"properties": {
"detail": {
"items": {
"properties": {
"loc": {
"items": {
"anyOf": [
{
"type": "string"
},
{
"type": "integer"
}
]
},
"type": "array",
"title": "Location"
},
"msg": {
"type": "string",
"title": "Message"
},
"type": {
"type": "string",
"title": "Error Type"
}
},
"type": "object",
"required": [
"loc",
"msg",
"type"
],
"title": "ValidationError"
},
"type": "array",
"title": "Detail"
}
},
"type": "object",
"title": "HTTPValidationError"
}POST /api/v1/storefront/orders/{order_id}/pay
Pay Storefront Order
Start a Paystack checkout for an already-created+submitted Sales Order — thin wrapper around the same accounting_payment_paystack.init_quote_like_payment that powers the public "Pay Now" link on a Quotation/Sales Order PDF (GET /paystack/pay-quote/{token}). Deliberately calls the service directly with the caller's own callback_url instead of reusing that GET route, which hardcodes a redirect back to this platform's own /portal — the external storefront needs its shopper landing back on its own checkout success page. Once Paystack confirms payment, the existing webhook (settlement == "quote_like") books the on-account Payment Entry automatically — no separate booking call needed from the caller.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
order_id | path | yes | integer |
Request body
json
{
"properties": {
"callback_url": {
"type": "string",
"title": "Callback Url"
}
},
"type": "object",
"required": [
"callback_url"
],
"title": "StorefrontOrderPayIn"
}200 — Successful Response
json
{
"properties": {
"ok": {
"type": "boolean",
"title": "Ok"
},
"authorization_url": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Authorization Url"
},
"reference": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Reference"
},
"message": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Message"
}
},
"type": "object",
"required": [
"ok"
],
"title": "StorefrontOrderPayOut"
}422 — Validation Error
json
{
"properties": {
"detail": {
"items": {
"properties": {
"loc": {
"items": {
"anyOf": [
{
"type": "string"
},
{
"type": "integer"
}
]
},
"type": "array",
"title": "Location"
},
"msg": {
"type": "string",
"title": "Message"
},
"type": {
"type": "string",
"title": "Error Type"
}
},
"type": "object",
"required": [
"loc",
"msg",
"type"
],
"title": "ValidationError"
},
"type": "array",
"title": "Detail"
}
},
"type": "object",
"title": "HTTPValidationError"
}POST /api/v1/settings/storefront/extract-favicon
Extract Favicon
Isolate the icon/symbol mark from an uploaded logo (dropping any wordmark) via Gemini image generation, and return it as a real transparent-background PNG. Mirrors app.grids.accounting's item-photo generator's green-screen-then-key-out trick — Gemini has no way to emit real alpha, so it's asked for a flat chroma-key background that gets keyed out server-side afterwards (see gemini_client.remove_green_screen). Pure preview: nothing is persisted here, the caller still has to Save.
Request body
json
{
"properties": {
"logo_url": {
"type": "string",
"maxLength": 750000,
"title": "Logo Url"
}
},
"type": "object",
"required": [
"logo_url"
],
"title": "ExtractFaviconIn"
}200 — Successful Response
json
{}422 — Validation Error
json
{
"properties": {
"detail": {
"items": {
"properties": {
"loc": {
"items": {
"anyOf": [
{
"type": "string"
},
{
"type": "integer"
}
]
},
"type": "array",
"title": "Location"
},
"msg": {
"type": "string",
"title": "Message"
},
"type": {
"type": "string",
"title": "Error Type"
}
},
"type": "object",
"required": [
"loc",
"msg",
"type"
],
"title": "ValidationError"
},
"type": "array",
"title": "Detail"
}
},
"type": "object",
"title": "HTTPValidationError"
}POST /api/v1/settings/storefront/generate-hero-image
Generate Hero Image
Generate a photographic hero banner from a text brief via Gemini image generation. Pure preview like extract_favicon: nothing is persisted here, the caller still has to Save (into branding.hero_image_url).
Request body
json
{
"properties": {
"prompt": {
"type": "string",
"maxLength": 500,
"title": "Prompt"
}
},
"type": "object",
"required": [
"prompt"
],
"title": "GenerateHeroImageIn"
}200 — Successful Response
json
{}422 — Validation Error
json
{
"properties": {
"detail": {
"items": {
"properties": {
"loc": {
"items": {
"anyOf": [
{
"type": "string"
},
{
"type": "integer"
}
]
},
"type": "array",
"title": "Location"
},
"msg": {
"type": "string",
"title": "Message"
},
"type": {
"type": "string",
"title": "Error Type"
}
},
"type": "object",
"required": [
"loc",
"msg",
"type"
],
"title": "ValidationError"
},
"type": "array",
"title": "Detail"
}
},
"type": "object",
"title": "HTTPValidationError"
}GET /api/v1/settings/storefront
Get Settings
200 — Successful Response
json
{}PUT /api/v1/settings/storefront
Update Settings
Request body
json
{
"properties": {
"display_mode": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Display Mode"
},
"paystack_enabled": {
"anyOf": [
{
"type": "boolean"
},
{
"type": "null"
}
],
"title": "Paystack Enabled"
},
"published": {
"anyOf": [
{
"type": "boolean"
},
{
"type": "null"
}
],
"title": "Published"
},
"builder_chat_enabled": {
"anyOf": [
{
"type": "boolean"
},
{
"type": "null"
}
],
"title": "Builder Chat Enabled"
},
"store_name": {
"anyOf": [
{
"type": "string",
"maxLength": 255
},
{
"type": "null"
}
],
"title": "Store Name"
},
"tagline": {
"anyOf": [
{
"type": "string",
"maxLength": 255
},
{
"type": "null"
}
],
"title": "Tagline"
},
"branding": {
"anyOf": [
{
"properties": {
"logo_url": {
"anyOf": [
{
"type": "string",
"maxLength": 750000
},
{
"type": "null"
}
],
"title": "Logo Url"
},
"favicon_url": {
"anyOf": [
{
"type": "string",
"maxLength": 400000
},
{
"type": "null"
}
],
"title": "Favicon Url"
},
"hero_image_url": {
"anyOf": [
{
"type": "string",
"maxLength": 750000
},
{
"type": "null"
}
],
"title": "Hero Image Url"
},
"primary_color": {
"anyOf": [
{
"type": "string",
"maxLength": 20
},
{
"type": "null"
}
],
"title": "Primary Color"
},
"support_email": {
"anyOf": [
{
"type": "string",
"maxLength": 255
},
{
"type": "null"
}
],
"title": "Support Email"
},
"whatsapp_number": {
"anyOf": [
{
"type": "string",
"maxLength": 32
},
{
"type": "null"
}
],
"title": "Whatsapp Number"
},
"phone": {
"anyOf": [
{
"type": "string",
"maxLength": 32
},
{
"type": "null"
}
],
"title": "Phone"
},
"address": {
"anyOf": [
{
"type": "string",
"maxLength": 255
},
{
"type": "null"
}
],
"title": "Address"
}
},
"type": "object",
"title": "BrandingIn"
},
{
"type": "null"
}
]
},
"shipping_options": {
"anyOf": [
{
"items": {
"properties": {
"key": {
"type": "string",
"maxLength": 64,
"title": "Key"
},
"label": {
"type": "string",
"maxLength": 120,
"title": "Label"
},
"amount": {
"type": "number",
"title": "Amount",
"default": 0
}
},
"type": "object",
"required": [
"key",
"label"
],
"title": "ShippingOptionIn"
},
"type": "array"
},
{
"type": "null"
}
],
"title": "Shipping Options"
},
"template": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Template"
},
"value_props": {
"anyOf": [
{
"items": {
"properties": {
"title": {
"type": "string",
"maxLength": 80,
"title": "Title"
},
"description": {
"type": "string",
"maxLength": 200,
"title": "Description",
"default": ""
}
},
"type": "object",
"required": [
"title"
],
"title": "ValuePropIn"
},
"type": "array"
},
{
"type": "null"
}
],
"title": "Value Props"
},
"hero_eyebrow": {
"anyOf": [
{
"type": "string",
"maxLength": 120
},
{
"type": "null"
}
],
"title": "Hero Eyebrow"
},
"hero_heading": {
"anyOf": [
{
"type": "string",
"maxLength": 200
},
{
"type": "null"
}
],
"title": "Hero Heading"
},
"hero_subtext": {
"anyOf": [
{
"type": "string",
"maxLength": 500
},
{
"type": "null"
}
],
"title": "Hero Subtext"
},
"shipping_flat_base": {
"anyOf": [
{
"type": "number",
"minimum": 0
},
{
"type": "null"
}
],
"title": "Shipping Flat Base"
},
"shipping_flat_qty": {
"anyOf": [
{
"type": "integer",
"minimum": 0
},
{
"type": "null"
}
],
"title": "Shipping Flat Qty"
},
"shipping_flat_extra": {
"anyOf": [
{
"type": "number",
"minimum": 0
},
{
"type": "null"
}
],
"title": "Shipping Flat Extra"
}
},
"type": "object",
"title": "StorefrontIn",
"description": "Partial update — a field omitted (``None``) is left untouched."
}200 — Successful Response
json
{}422 — Validation Error
json
{
"properties": {
"detail": {
"items": {
"properties": {
"loc": {
"items": {
"anyOf": [
{
"type": "string"
},
{
"type": "integer"
}
]
},
"type": "array",
"title": "Location"
},
"msg": {
"type": "string",
"title": "Message"
},
"type": {
"type": "string",
"title": "Error Type"
}
},
"type": "object",
"required": [
"loc",
"msg",
"type"
],
"title": "ValidationError"
},
"type": "array",
"title": "Detail"
}
},
"type": "object",
"title": "HTTPValidationError"
}GET /api/v1/settings/storefront/pages
Get Pages
200 — Successful Response
json
{}PUT /api/v1/settings/storefront/pages
Set Pages
Request body
json
{
"properties": {
"pages": {
"additionalProperties": {
"type": "boolean"
},
"type": "object",
"title": "Pages"
}
},
"type": "object",
"required": [
"pages"
],
"title": "PageToggleIn"
}200 — Successful Response
json
{}422 — Validation Error
json
{
"properties": {
"detail": {
"items": {
"properties": {
"loc": {
"items": {
"anyOf": [
{
"type": "string"
},
{
"type": "integer"
}
]
},
"type": "array",
"title": "Location"
},
"msg": {
"type": "string",
"title": "Message"
},
"type": {
"type": "string",
"title": "Error Type"
}
},
"type": "object",
"required": [
"loc",
"msg",
"type"
],
"title": "ValidationError"
},
"type": "array",
"title": "Detail"
}
},
"type": "object",
"title": "HTTPValidationError"
}POST /api/v1/settings/storefront/domain
Set Domain
Kick off custom-domain provisioning: validates the hostname, checks it isn't already claimed by another site, then queues the DNS-check + nginx/certbot automation as a background job (can take up to ~a minute — see :func:app.services.storefront_provisioning.provision_domain).
Request body
json
{
"properties": {
"domain": {
"type": "string",
"maxLength": 253,
"title": "Domain"
}
},
"type": "object",
"required": [
"domain"
],
"title": "DomainIn"
}200 — Successful Response
json
{}422 — Validation Error
json
{
"properties": {
"detail": {
"items": {
"properties": {
"loc": {
"items": {
"anyOf": [
{
"type": "string"
},
{
"type": "integer"
}
]
},
"type": "array",
"title": "Location"
},
"msg": {
"type": "string",
"title": "Message"
},
"type": {
"type": "string",
"title": "Error Type"
}
},
"type": "object",
"required": [
"loc",
"msg",
"type"
],
"title": "ValidationError"
},
"type": "array",
"title": "Detail"
}
},
"type": "object",
"title": "HTTPValidationError"
}DELETE /api/v1/settings/storefront/domain
Clear Domain
200 — Successful Response
json
{}GET /api/v1/settings/storefront/domain/status
Domain Status
Lightweight poll target for the builder form's domain status badge.
200 — Successful Response
json
{}POST /api/v1/settings/storefront/temp-domain
Set Temp Domain
Provision an instant <label>.erpcloud.co.za subdomain — unlike /domain, no DNS action is needed from the caller (the platform owns that zone); the DNS record itself is created as part of the background job. Independent of /domain — both can be live on the same site at once.
Request body
json
{
"properties": {
"label": {
"type": "string",
"maxLength": 32,
"title": "Label"
}
},
"type": "object",
"required": [
"label"
],
"title": "TempDomainIn"
}200 — Successful Response
json
{}422 — Validation Error
json
{
"properties": {
"detail": {
"items": {
"properties": {
"loc": {
"items": {
"anyOf": [
{
"type": "string"
},
{
"type": "integer"
}
]
},
"type": "array",
"title": "Location"
},
"msg": {
"type": "string",
"title": "Message"
},
"type": {
"type": "string",
"title": "Error Type"
}
},
"type": "object",
"required": [
"loc",
"msg",
"type"
],
"title": "ValidationError"
},
"type": "array",
"title": "Detail"
}
},
"type": "object",
"title": "HTTPValidationError"
}DELETE /api/v1/settings/storefront/temp-domain
Clear Temp Domain
200 — Successful Response
json
{}GET /api/v1/settings/storefront/temp-domain/status
Temp Domain Status
200 — Successful Response
json
{}