System Design for Checkout (Commercetools) — A Guide for Developers
What a production-grade checkout on Commercetools with Stripe or Braintree needs: idempotency, minimal PCI scope, immutable records, correct money storage, and webhook-driven payment events.
- system-design
- commercetools
- checkout
- payments
- security
- node
Designing a reliable and secure checkout system requires a solid understanding of certain foundational principles, particularly when working with headless commerce platforms like Commercetools and integrating with Stripe or Braintree.
Let's go over a few critical concepts.
Idempotency
Definition: Idempotency ensures that making the same request multiple times has the same effect as making it once. This is particularly important in payments where duplicate network requests (due to retries or user error) must not result in double charges.
Example in Node.js middleware:
let idempotencyDB = {};
const idempotencyMiddleware = (req, res, next) => {
if (req.method === 'POST') {
//get the key from the header
const idempotencyKey = req.headers['Idempotency-Key'];
if (idempotencyKey) {
if (idempotencyDB[idempotencyKey]) {
return res.status(200).json(idempotencyDB[idempotencyKey]);
} else {
res.on('finish', () => {
idempotencyDB[idempotencyKey] = res.locals.response;
});
}
}
}
next();
};
app.use(idempotencyMiddleware);
Note: In production systems, use a durable store like Redis instead of an in-memory cache.
PCI Compliance (Payment Card Industry Data Security Standard)
Security is non-negotiable when handling payment data. If you are integrating a PSP, your goal should be to minimize your PCI scope as much as possible.
- Never store raw card details: Instead, use tokens provided by PSPs like Stripe or Braintree.
- Use strong encryption: Data in transit should be encrypted using TLS. Sensitive data at rest (e.g., billing info) must be encrypted using strong algorithms like AES-256.
- Authentication & Access Control: Restrict access to payment data using roles and permission controls.
- Regular Security Scanning: Automate vulnerability scanning. For example, GitHub offers security analysis in the Security tab using tools like Dependabot:

- Avoid storing PII: Save only the user ID or payment method token (e.g.,
paymentMethodId) to retrieve payment details via the PSP's API. - Implement strong access control measures: Access to cardholder data must be restricted to only those who need it. Developers need to build systems that enforce user roles and permissions effectively.
Immutable and Durable Systems
Immutability means that once a record (e.g., a transaction) is written, it should not be changed. This makes the system auditable and helps with debugging.
Durability refers to the ability to persist data reliably even in the case of system crashes.
- Write logs and records in an append-only fashion.
- Use event sourcing or audit logs to record each state change.
- Save payment data in the smallest grain possible. For example:
- Represent money in cents or micros instead of floats.
- Prefer
DECIMAL(19,4)for currency precision across international transactions.
Handling Money in Databases
Financial amounts must be stored with accuracy and consistency.
Use the Right Data Type
- For U.S. dollars only: Store values in cents (
INT). - For global currency support: Use
DECIMAL(19, 4)or greater (depending on business needs).
Avoid Floating Point Math
// ❌ Don't do this
let total = 0.1 + 0.2; // 0.30000000000000004
// ✅ Use integer math (in cents)
let totalCents = 10 + 20; // 30
Consistent Rounding
Standardize rounding (e.g., Banker's Rounding) and apply it consistently in both backend and frontend.
Payment Events & Webhooks
When integrating with external PSPs, event-driven design is essential to reflect the true state of payments in your system.
Set up webhook handlers for these key events:
| Event | Description |
|---|---|
authorize | Card has been validated, and funds are reserved. |
capture | Funds have been transferred. Usually occurs after fulfillment. |
cancel | Payment was voided before being captured. |
refund | Funds were returned to the customer after capture. |
Architecture Recommendation
- Create a
payments-servicethat listens to webhooks. - On event receipt:
- Validate the webhook (e.g., signature verification).
- Update the associated order/payment status in Commercetools.
- Store the raw event payload for audit purposes.
Example Architecture Diagram

If you're designing a checkout system using Commercetools, Stripe, or Braintree, adhering to these principles ensures security, accuracy, and auditability — the hallmarks of a production-grade payment system.
Originally published on Medium on July 11, 2025.