Snapshotting Tax at Checkout

Snapshotting Tax at Checkout

Congratulations on making it to the final lesson in this path! 🎉 You have come a long way—from building foundational APIs, to managing carts and orders, to applying country-based taxes before checkout. This last step brings everything together in one of the most important moments in an e-commerce backend: turning a live cart into a permanent order snapshot.

In this lesson, we will focus on preserving tax history at checkout time. That means the order should store the exact tax_country, tax_rate_bps, tax_cents, and total_cents that were true at the moment checkout happened. Even if tax rates change later, old orders must not change with them. By the end of this lesson, you will see how the checkout transaction captures those values, why reads must return the stored snapshot instead of recomputing tax, and how the repository keeps order data consistent across both list and get-by-id reads.

Previously, we made carts tax-aware by allowing a cart to store a tax_country and by deriving cart totals from the current tax_rates configuration. That was the right behavior for a cart, because carts are still editable and should reflect current pricing rules. Orders are different: once checkout succeeds, their financial values must become permanent.

Why Checkout Needs a Tax Snapshot

A cart is allowed to change. A user can add items, remove items, switch quantities, or even change the country used for tax calculation. Because of that, cart totals should always reflect the current state of the cart and the current tax configuration.

An order is not like that. Once checkout succeeds, the order becomes a historical record of what the customer actually agreed to pay. If a tax rate for US changes tomorrow, that should affect future carts and future checkouts, but it should never rewrite an existing order from yesterday.

That is why checkout must snapshot tax data. Instead of storing only the final tax_cents, we also persist the tax_country and the exact tax_rate_bps used during checkout. That gives us both the result and the context behind the result, which is useful for receipts, order history, debugging, and accounting.

The Order Row Must Include Tax Snapshot Fields

The first place this lesson touches is src/lib/repositories/ordersRepo.ts. Since orders are supposed to preserve tax details, the repository’s database row type must include those fields explicitly.

This is important because the repository is the layer that converts raw database rows into domain objects. If the row type omits tax_country or tax_rate_bps, those values will never make it into the Order returned by the rest of the application.

export interface OrderRow {
  id: string;
  cart_id: string;
  status: string;
  subtotal_cents: number;
  tax_cents: number;
  total_cents: number;
  tax_country: string | null;
  tax_rate_bps: number;
  currency: string;
  created_at: string;
  updated_at: string;
}
  • This row type mirrors the important persisted columns in the orders table, including both tax_country and tax_rate_bps. That matters because a checkout snapshot is only useful if the repository actually reads those stored values back out of the database.

  • Including tax_country gives clients the geographic context used for tax resolution at checkout time. Including tax_rate_bps gives clients the exact rate that produced the stored tax_cents, which is especially helpful when explaining old orders after tax policies have changed.

  • These fields are not optional extras in this workflow. They are part of the order’s financial record, and keeping them in the row type ensures the repository remains aligned with the database schema and the domain model.

Sign up

Join the 1M+ learners on CodeSignal

Be a part of our community of 1M+ users who develop and demonstrate their skills on CodeSignal