DW Alliance store
An online store built into every DW Alliance brand: a product catalog, carts, checkout, invoices, payment records and shipments, all in US dollars. Your customers shop on your own domain; you manage the store with your DW Alliance session.
How it fits together
- Brand. Everything belongs to one brand. On a customer domain (for example
shop.example.com) the brand is worked out from the domain name, so customers never need to know it. - Companies. A product is sold by one or more companies on the brand (a "claim"). Each category belongs to one company. A cart, its invoice, payments and shipments belong to the company selling the goods.
- Products and variants. Every product has at least one variant (size, colour, pack). Creating a product creates a
Defaultvariant in the same step. Carts and orders always point at a variant. - Orders. Checkout turns a cart into a PENDING invoice with its lines, plus a copy of the shipping and billing address as they were at the time of the order. Payments move it to PAID; shipments send the goods.
- Money. US dollars only, two decimals, sent as text such as
"19.99". Tax and shipping start at 0.00 and the store adds them on the invoice.
Who can do what
| Who | How they are recognised | Can |
|---|---|---|
| Visitor | Nothing. Calls are made on the store's own domain. | Browse products, categories and search; build a cart. |
| Customer | Signed in on the store's domain with an email code (a secure cookie, 30 days). | Everything a visitor can, plus addresses, checkout, own invoices, payment records and shipment tracking. |
| Store staff | session and brand from /session/ in the JSON body. | Manage products, variants, descriptions, images, categories, invoices, payments and shipments. Needs SUPER_ADMIN, a STORE right on the brand (CREATE, UPDATE, DELETE, READ or WRITE), or to be an EDITOR of a domain owned by the company concerned. |
STORE rights are granted like any other right with /permissions/. Domain editors can manage the products and categories of the company that owns their domain.
Set up a store
- Have a DW Alliance account and brand (/account_setup/) and a company on it.
- Claim your domain with /domain/ for that company and point it at DW Alliance hosting (steps 4 to 7 on the app home page).
- Start a staff session with /session/.
- Create categories and products (below). Upload product photos with /files/ and attach them.
- Build your shop pages as normal HTML files on your domain. They call the store endpoints on the same domain with
fetch().
Products, variants and categories
Create a product
POST https://app.dwalliance.com/store/product/
{"action":"create","session":"...","brand":"...","company_id":"...",
"name":"Kona Coffee 1 lb","price":"24.00","stock":40,
"description":"Medium roast from Holualoa."}
The answer has product_id, slug (made from the name and unique on the brand), the default variant_id and the description_id. Leave stock out to not track stock.
Variants
/store/product/variants/actioncreatewithproduct_id,nameand optionalprice(blank uses the product price),stock,position.- A product always keeps at least one variant. A variant that is in a cart or an order cannot be deleted.
Descriptions and images
/store/product/description/keeps one description perused_location(for examplemain,short,care)./store/product/images/attaches a/files/file (on the same brand) to a product, a variant or a category, with apositionfor ordering.
Categories
- Categories belong to one company and can be nested with
parent_id(same company). - Action
linkputs a product in a category. The product must be claimed by the category's company.
Several sellers
Action claim on /store/product/ lets another company on the brand sell the same product. A cart is always for one company; if a product has several sellers the cart must say which (company_id).
Retiring a product
Set active to false to hide it. Products that are already in a cart or an order cannot be deleted, so past orders stay complete.
Customer accounts and sign-in
These calls are made on your own domain, never on app.dwalliance.com. Codes are only ever sent by email.
- New customer: POST
{"action":"request_code","email":"..."}to/end_user_account_setup/. A 6-character code is emailed and lasts 30 minutes. - POST
{"action":"verify","id":"...","confirmation_id":"..."}. The customer is now signed in for 30 days on that domain. - Then
{"action":"profile",...}adds their name, company name, phone, and shipping or billing address. - Returning customer: POST
{"action":"request_code","email":"..."}to/customer_session/, thenverifywith the returnedidand the emailedcode.whoamiandlogoutare also available.
Sign-up is US-only, blocks VPN and Tor traffic, and is rate limited. Unfinished sign-ups are deleted after 90 days.
Customer addresses
/address/ creates, edits, lists and deletes addresses. A signed-in customer manages their own; staff can manage people and companies on their brand. Checkout uses one shipping address and one billing address from this list.
POST /address/ {"action":"create","line_1":"75-5660 Palani Rd","city":"Kailua-Kona","state":"HI","zipcode":"96740","address_type":"Shipping"}
Carts
- POST
{"action":"add","variant_id":"...","quantity":2}to/store/cart/. Withoutcart_ida new cart is made and its id is returned. Keep it (for example inlocalStorage) and send it on later calls. - Cart ids are long random server ids; nobody can choose their own. Adding the same variant again raises the quantity (one line per variant).
- Actions
update(quantity 0 removes),remove,readanddelete. Signed-in customers can usemineto find their open carts on any device. - When a signed-in customer touches an anonymous cart, it becomes theirs and only they can see it.
Checkout and invoices
POST /store/checkout/
{"action":"checkout","cart_id":"...","shipping_address_id":"...","billing_address_id":"..."}
- Needs a signed-in customer. Stock and availability are checked, stock is reduced, and a PENDING invoice is created with
cart_id, lines (product, variant, name and price at the time), and SHIPPING and BILLING address copies. - A cart can be checked out once.
- Customers read their own invoices with
/store/invoice/(read,list). Staff can list by company and status, set tax and shipping while PENDING (the total is recalculated), or mark an invoice VOIDED or REFUNDED.
Payments
- Staff record payments with
/store/invoice/payment/:amount,method(CASH, CARD, PAYPAL or OTHER) and optionalprovider_ref. When completed payments reach the total, the invoice becomes PAID. - Amounts can never be more than the balance due.
Online card and PayPal processing is not connected yet. A customer's CARD or PAYPAL request is recorded as PENDING and no charge is made; the store confirms the payment (for example after an invoice is paid by phone or in person) by marking it COMPLETED.
Shipments
- Staff create shipments with
/store/shipment/: theinvoice_id, a list ofitems(invoice_product_idandquantity), and optionalcarrier,service,tracking_number,tracking_url(https only) andshipping_cost. - An order can ship in several parts. You cannot ship more than was ordered (cancelled shipments do not count).
- Status: PENDING, LABEL_CREATED, SHIPPED, IN_TRANSIT, DELIVERED, RETURNED, CANCELLED. Shipped and delivered dates are filled in automatically.
- Every shipment goes to the order's shipping address copy. Customers can read their shipments and tracking links.
History and safety
- Every create, update and delete keeps a history copy of the row, so changes can be traced and undone.
- Sign-in codes, session ids and brand codes are never returned in JSON. The customer session is an HttpOnly, Secure cookie tied to one domain.
- Every store row is kept to its brand; staff only see companies they are allowed to act for.
Endpoint reference
POST JSON with an action. A GET (or a POST with no action) on any path returns its list of actions. Staff add session and brand to the body.
| Path | Actions | Who |
|---|---|---|
/store/products/ | list, read | Public |
/store/products/categories/ | list | Public |
/store/search/ | search (q) | Public |
/store/product/ | create, update, delete, claim, unclaim | Staff |
/store/product/variants/ | list (public), create, update, delete | Staff |
/store/product/description/ | create, update, delete | Staff |
/store/product/categories/ | create, update, delete, link, unlink | Staff |
/store/product/images/ | create, update, delete | Staff |
/store/cart/ | add, update, remove, read, mine, delete | Public / customer |
/store/checkout/ | checkout | Customer |
/store/invoice/ | read, list, update | Customer (own) / staff |
/store/invoice/payment/ | create, update, list | Customer (own) / staff |
/store/shipment/ | create, update, delete, read, list | Staff / customer (read) |
/address/ | create, update, delete, read, list | Customer (own) / staff |
/end_user_account_setup/ | request_code, verify, status, profile | Customer, on your domain |
/customer_session/ | request_code, verify, whoami, logout | Customer, on your domain |
Always include the trailing slash, for example /store/cart/. Errors come back as {"ok":false,"error":"..."} with a matching HTTP status.