E-commerce Development
Conversion-focused storefronts that run without manual intervention.
An e-commerce site that works is one where a customer can discover a product, pay, and receive an order confirmation without a single member of your team doing anything. That sounds basic, but getting payments, inventory, fulfilment, tax and customer accounts all integrated and reliable is a genuine engineering project. We have done it many times.
We build both: fully custom storefronts on a headless stack for brands that need something a theme cannot deliver, and Shopify or WooCommerce implementations for businesses that need to move fast and want a familiar admin. Either way, the store is yours, the data is yours and the integrations are documented so you can hand it to a developer who did not build it.
What this covers
Custom headless storefronts (Next.js + Stripe / Medusa / custom cart) or Shopify / WooCommerce builds
Product catalogue, collections, variants, bundles and digital goods
Checkout optimisation: single-page checkout, guest checkout, saved cards, applied discounts
Payment gateway integration: Stripe, Razorpay, PayPal and regional providers
Inventory management, low-stock alerts and integration with 3PL or fulfilment APIs
Transactional email flows: order confirmation, shipping updates, abandoned cart recovery
SEO: structured data, canonical URLs, paginated collections and Core Web Vitals performance
Deliverables
- A live, conversion-optimised storefront on a domain and hosting you own
- Payment, inventory and fulfilment integrations fully tested end-to-end
- Source code or Shopify theme with documentation and an admin walkthrough
- Transactional email flows and a basic analytics baseline in place at launch
What we build with
How we engineer e-commerce systems
E-commerce sites fail in predictable ways: checkout flows that lose orders on payment errors, inventory counts that desynchronise from the warehouse, performance that collapses under a promotion spike, and PCI scope that grows until it becomes a compliance liability. These principles are the direct response to each of those failure modes.
Checkout is a distributed transaction — design it that way
A checkout involves at minimum: inventory reservation, payment authorisation, order record creation, and confirmation email dispatch. Each of these can fail independently. A naive implementation that calls them in sequence without compensation logic creates ghost orders (payment taken but no order created), double-charges (payment retried after a timeout), and false out-of-stock errors (inventory reserved but payment failed without releasing it). We model the checkout as a state machine with explicit compensation for every failure branch.
Idempotency keys on every payment operation
Network timeouts during payment calls are not exceptional events — they are routine. If the client does not receive a response and retries the request without an idempotency key, the payment gateway may process the charge twice. We attach a stable, order-scoped idempotency key to every Stripe or Razorpay charge creation call. The gateway deduplicates on its side; we deduplicate on ours by checking the key before creating a new payment intent.
Inventory reservation before payment capture
Authorising payment and then discovering the item is out of stock is a customer-experience failure that erodes trust and generates chargebacks. We reserve inventory atomically (typically with a database-level SELECT FOR UPDATE or a Redis atomic decrement) at checkout initiation, hold the reservation for a short window, and release it if payment is not completed within that window. Capture occurs only after a confirmed reservation.
Minimise PCI scope through hosted payment fields
Any surface that handles raw card data falls under PCI DSS SAQ D requirements — the most demanding self-assessment questionnaire, with controls that add significant compliance overhead. We use hosted payment fields (Stripe Elements, Razorpay Checkout) that render in an iframe from the payment provider’s domain. Card data never touches your server or your DOM; scope reduces to SAQ A, which is manageable for most merchants.
Performance is a conversion metric
Google’s research consistently shows that each 100 ms increase in load time reduces conversion rate. Product listing pages and the cart are the highest-impact targets. We set explicit Core Web Vitals budgets at the start of a project, enforce them in CI with Lighthouse CI, and treat a budget regression as a build failure. Strategies include server-side rendering of product pages, aggressive image optimisation with next/image, and CDN-edge caching for catalogue responses.
Transactional emails are part of the order contract
A customer who pays and receives no confirmation email has a support ticket, a possible chargeback, and a lost second purchase. We wire transactional email flows (order confirmation, shipping notification, delivery confirmation, return initiated) to order state transitions at build time, not as a post-launch task. Each email template is tested with a preview endpoint and verified against real order fixtures before launch.
How we'd choose
There's rarely one right answer — these are the trade-offs we weigh before recommending an approach.
Headless commerce vs Platform (Shopify / Medusa) vs Fully custom
This decision determines your time-to-market, your flexibility ceiling, and the ongoing operational surface your team must own. It is also not binary — a Shopify backend with a custom Next.js storefront (Shopify Hydrogen or a bespoke frontend) occupies the middle ground that many projects land in.
| Criterion | Platform-native (Shopify / WooCommerce) | Headless (Shopify/Medusa backend + custom frontend) | Fully custom (bespoke stack) |
|---|---|---|---|
| Time to launch | Fastest — theme-based stores can go live in days; admin, payments, and fulfilment integrations are pre-built | Moderate — frontend build takes weeks; backend platform handles payments, orders, and inventory | Longest — every subsystem is built from scratch: product catalogue, cart, checkout, order management, payments |
| Checkout customisation | Limited on Shopify (Checkout Extensibility for Plus merchants); WooCommerce gives more flexibility but requires plugin management | Full control over the frontend checkout UX; backend constraints depend on platform (Shopify’s checkout cannot be fully replaced on most plans) | Complete control — multi-step, single-page, split-payment, custom discount logic, or non-standard fulfilment flows are all achievable |
| Admin and operations | Shopify’s admin is mature, well-documented, and familiar to most e-commerce operations teams; staff training cost is low | Platform admin handles orders, inventory, and fulfilment; frontend changes require a developer | Custom admin must be built and maintained; operations team learns a bespoke interface with no community documentation |
| Integration with existing systems | Large ecosystem of pre-built apps (ERPs, 3PLs, CRMs) via the Shopify App Store; custom integrations use the REST or GraphQL Admin API | Platform API is available for integrations; headless architecture makes it straightforward to add services between the frontend and the backend | Full control over integration design; no third-party API constraints, but every integration is custom-built |
| Total cost of ownership | Predictable platform fee plus per-transaction fee; scales with revenue; no infrastructure to operate | Platform fee plus frontend hosting cost; lower transaction fees possible with Shopify Plus; some infrastructure to own | No platform fee; all infrastructure, security patching, PCI compliance, and payment gateway costs are owned entirely by you |
| When to choose | Standard catalogue commerce with conventional checkout flows and a team that needs to operate independently of developers day-to-day | Brands that need a bespoke storefront experience, performance-critical frontend, or content-commerce integration that a Shopify theme cannot express | Marketplaces, rental platforms, B2B ordering portals, or any commerce model where the checkout logic, pricing rules, or fulfilment flow genuinely cannot be expressed in an available platform |
Anti-patterns we prevent in e-commerce builds
No compensation logic in checkout
The checkout handler calls inventory reservation, then payment, then order creation in sequence. When the payment succeeds but the order creation fails (database timeout, constraint violation), the customer is charged but has no order. When the order creation succeeds but the confirmation email fails, the customer has an order they do not know exists. Both scenarios generate chargebacks and support escalations that cost more to resolve than the original order was worth.
Model the checkout as a state machine: INITIATED → INVENTORY_RESERVED → PAYMENT_AUTHORISED → ORDER_CREATED → CONFIRMED. Each state transition is persisted before the next step is attempted. A background job reconciles checkouts stuck in intermediate states: releasing inventory for sessions that expired without payment capture, and retrying confirmation emails for orders that were created but not confirmed. The payment gateway’s idempotency key is tied to the checkout ID so retries are safe.
PCI scope expanded by logging card-adjacent data
The application logs the full request body on payment endpoints ‘for debugging’, or stores the raw Stripe response including the last four digits, expiry, and billing address in an application database table. PCI DSS 4.0 Requirement 3 treats storage of sensitive authentication data (including cardholder name combined with PAN fragments) as in-scope even if the data is never used. A single log line containing a card BIN and an email address can expand your SAQ level.
Scrub payment-related request and response bodies from application logs before they are written. Use Stripe’s native storage for card metadata (payment method objects) and reference them by ID only. Enforce log scrubbing in your logging middleware with a tested list of prohibited fields. Run a quarterly PCI scope review to confirm no new logging paths have been introduced.
Inventory managed exclusively in the e-commerce database
The product’s available_stock column is the system of record for inventory. A flash sale drives concurrent checkout requests; each reads available_stock, decrements it, and writes it back. Without pessimistic locking or atomic operations, two concurrent checkouts can read the same stock level, both reserve the last unit, and both succeed. The warehouse ships one item and the second customer receives an apology email.
Use database-level atomic operations for inventory reservation: a single UPDATE products SET reserved_stock = reserved_stock + 1 WHERE id = $1 AND (total_stock - reserved_stock) >= $2 RETURNING id. The affected row count tells you whether the reservation succeeded without a preceding read. For high-concurrency scenarios (flash sales), replace the database counter with a Redis atomic DECRBY and sync back to the database asynchronously for durability.
Common questions
Should we use Shopify or build a custom storefront?
Shopify wins on time-to-launch and admin simplicity for standard catalogue commerce. A custom build wins when your checkout logic, product configuration or customer journey cannot be expressed in what Shopify allows — which is less common than people assume. We will scope both and recommend the one that fits your timeline and long-term flexibility.
Can you integrate with our existing ERP or warehouse management system?
Yes. ERP and WMS integrations are a standard part of e-commerce builds at scale — we have connected Shopify and custom stores to SAP, Tally, Unicommerce and bespoke warehouse APIs. The approach depends on whether the system has a documented API or requires scheduled data exchange.
Related capabilities
Have something in mind?
Tell us what you're building or stuck on. The first consultation is free — no obligation, no hard sell.