Customer quote requests
Collect a customer’s products, quantities, and requirements without turning a request into an order.
Build a request-a-quote form for bulk purchases or custom requirements. Signed-in customers submit a request and can return to see its status. You inspect requests and update progress through your agent, with the workflow and fields chosen for your store.
Use Littleworks to build a quote-request workflow for my Shopify store. Signed-in customers should submit product variants, quantities, and requirements, then check their request status. Store requests in Littleworks and let me update them through my agent. Start with request tracking, without creating orders or sending emails. Read https://littleworks.app/docs/recipe-quote-requests.md and adapt it to my store.What you are building
- A form containing selected variants, quantities, and a bounded requirements field.
- A receipt with a request reference and a customer page showing new, reviewing, replied, or closed status.
- A private merchant work for status updates, internal notes, and an optional customer-visible response. No automatic order, payment, or inventory reservation.
Where the data lives
Use feature quotes and collection requests. A document holds customerId, requestKey, a bounded items array, requirements, status, optional publicReply, and optional internalNote. Store a timestamped catalog snapshot only if useful, with its currency and country; label it as a reference, not an agreed quote. The document is the authoritative request record.
Littleworks collections fit the custom lifecycle and private customer access. Shopify remains the authority for products and any later draft order. There is no need to create an order or metaobject for every inquiry. The Littleworks Data page supports inspection; records change through the works, not an assumed inline editor.
Before you build
- Verify customer access through the storefront’s app proxy. The baseline gets customerId from context and does not ask the browser to prove identity with an email address.
- Use the included Storefront catalog access to resolve selected variants. If the merchant needs unpublished products, choose and authorize the separate Admin catalog workflow explicitly.
- Read usage and set an input size that fits a 16 KiB document including server-added fields. A useful starting bound is 10 line items, positive integer quantities up to 10,000, and requirements up to 2,000 characters; also check serialized UTF-8 byte size.
The works to build
| Work | Entry point | Behavior |
|---|---|---|
| quotes.submit | Customer HTTP POST | Validate the request, resolve variants, and store it once |
| quotes.list | Customer HTTP GET or POST | Read a bounded page of this customer’s requests with public fields only |
| quotes.update | Private callable | Check revision and allowed transitions; save merchant status, notes, or reply |
All works share feature quotes. Establish ensureUnique(["customerId", "requestKey"]) during setup for each intended environment. Store one submission per customer + request key, and keep its submitted fields immutable. Status and merchant replies are separate changes. Use an explicit input schema that rejects client-supplied status, internal notes, prices, and customer IDs.
Implementation outline for the agent
- Capture the intent. The frontend creates a request key for the current submission and retains it while the outcome is uncertain. Send variant IDs, quantities, requirements, and the selected country/language. Disallow duplicate variant lines or normalize them before saving. Escape all customer-written text when displaying it.
- Validate on the server. Derive customer identity from context.customer.id. Resolve the variants through shopify.storefront.graphql with explicit localization, verify each result, and enforce quantity and size bounds. A quote request may intentionally include out-of-stock products if the merchant chooses; being saved does not reserve inventory or guarantee availability.
- Store once. Look up the customer + requestKey, then create under the persistent uniqueness rule. If another request wins the race, load that record. Return the same receipt only when the original submitted payload matches; otherwise reject key reuse. The receipt contains the request ID and status, not internal fields.
- Let the customer check progress. Filter every list by the verified customer ID and paginate. Project only request ID, their submitted items/requirements, status, publicReply, and dates. Never return the entire document: internalNote must remain private even after it is added later.
- Support merchant updates. The private callable work loads the current revision and enforces the agreed transition rules. Use a revision-checked patch or update. Only explicitly designated publicReply content is shown to customers. A revision conflict requires reassessment; it must not silently replace another merchant action.
Add notifications only when needed
The baseline uses a confirmation page and customer status page. An email provider or CRM can be added through secrets and external requests, if the store’s plan permits it. Save the request before attempting delivery, track delivery state separately, and use the provider’s idempotency support. An email failure must not lose the request or create another submission. There is no built-in mail service, scheduled follow-up, or durable notification queue.
Acceptance checks
- The same customer can submit, reload, and view a request. Another customer cannot retrieve it or see internal notes.
- A forged customer ID, client-set price/status, invalid variant, excessive quantity, or oversized body is rejected.
- A double click or concurrent submission with the same request key returns one receipt. Reusing the key with different content fails clearly.
- Concurrent merchant updates respect revisions. A customer cannot invoke the private update work.
- The page handles sign-in, empty requests, pagination, and limits. No order is created, inventory reserved, or email sent by the baseline.
Make it yours
Add a merchant-approved draft-order conversion using the optional write_draft_orders scope. Link the returned draft order to the request and reconcile uncertain outcomes before repeating a creation. A guest inquiry form is another extension: it needs a deliberate contact-verification and private-status-access design. An email address or request ID alone is not proof of ownership.