# Require a minimum order value

> A Shopify validation Function that blocks checkout below a minimum order value set in your store currency and converted for each market. Tested JavaScript.

Page: https://lintelagency.com/resources/shopify-functions/minimum-order-value

## In short

This validation Function blocks checkout when the cart subtotal is below a minimum, 500 in your store currency by default, converted to the customer’s currency. Customers can still build their cart freely; the rule applies from checkout on. It uses the cart.validations.generate.run target of the Cart and Checkout Validation API, version 2026-10, on any plan in a public app.

## Facts

- **Function API:** Cart and Checkout Validation
- **Target:** cart.validations.generate.run
- **Plan:** Any plan in a public app; Shopify Plus in a custom app
- **App scope:** write_validations
- **API version:** 2026-10
- **Last checked:** 2 November 2026

## How to use it

1. Create an app with the Shopify CLI and add the extension: shopify app generate extension --template cart_checkout_validation, with JavaScript.
2. Replace the generated shopify.extension.toml and the two files in src/ with the files below.
3. Run the fixtures with shopify app function run --input tests/below-minimum-at-checkout.input.json.
4. Deploy with shopify app deploy and turn the validation on with validationCreate.
5. Set the minimum and message in the validation’s $app:function-configuration metafield, for example {"minimumAmount": 250}.

## Code

### shopify.extension.toml

```toml
api_version = "2026-10"

[[extensions]]
name = "Minimum order value"
handle = "minimum-order-value"
type = "function"

  [[extensions.targeting]]
  target = "cart.validations.generate.run"
  input_query = "src/cart_validations_generate_run.graphql"
  export = "cart-validations-generate-run"

  [extensions.build]
  command = ""
  path = "dist/function.wasm"
```

### src/cart_validations_generate_run.graphql

```graphql
query CartValidationsGenerateRunInput {
  buyerJourney {
    step
  }
  cart {
    cost {
      subtotalAmount {
        amount
      }
    }
  }
  presentmentCurrencyRate
  validation {
    metafield(namespace: "$app", key: "function-configuration") {
      jsonValue
    }
  }
}
```

### src/cart_validations_generate_run.js

```js
// @ts-check

/**
 * @typedef {import("../generated/api").CartValidationsGenerateRunInput} CartValidationsGenerateRunInput
 * @typedef {import("../generated/api").CartValidationsGenerateRunResult} CartValidationsGenerateRunResult
 */

/** Settings stored as JSON in the validation's metafield. */
const DEFAULT_CONFIG = {
  // In the store's currency; converted to the customer's currency below.
  minimumAmount: 500,
  // {amount} is replaced with the converted minimum.
  message: "The minimum order value is {amount}. Add a few more items to check out.",
};

/** Errors about the cart as a whole show at the top of checkout and on the cart. */
const CART_TARGET = "$.cart";

/** @type {CartValidationsGenerateRunResult} */
const NO_ERRORS = { operations: [] };

/**
 * @param {CartValidationsGenerateRunInput} input
 * @returns {CartValidationsGenerateRunResult}
 */
export function cartValidationsGenerateRun(input) {
  // Let customers keep adding to the cart freely; enforce the rule from checkout on.
  if (input.buyerJourney.step === "CART_INTERACTION") return NO_ERRORS;

  const config = { ...DEFAULT_CONFIG, ...input.validation?.metafield?.jsonValue };
  // The cart is priced in the customer's currency; the minimum is set in the store's.
  const minimum = config.minimumAmount * Number(input.presentmentCurrencyRate);
  const subtotal = Number(input.cart.cost.subtotalAmount.amount);
  if (subtotal >= minimum) return NO_ERRORS;

  const message = config.message.replace("{amount}", minimum.toFixed(2));
  return { operations: [{ validationAdd: { errors: [{ message, target: CART_TARGET }] } }] };
}
```

## Test input and expected output

### tests/below-minimum-at-checkout.input.json

```json
{
  "buyerJourney": { "step": "CHECKOUT_COMPLETION" },
  "cart": { "cost": { "subtotalAmount": { "amount": "420.0" } } },
  "presentmentCurrencyRate": "1.0",
  "validation": { "metafield": null }
}
```

### tests/below-minimum-at-checkout.output.json

```json
{
  "operations": [
    {
      "validationAdd": {
        "errors": [
          { "message": "The minimum order value is 500.00. Add a few more items to check out.", "target": "$.cart" }
        ]
      }
    }
  ]
}
```

### tests/below-minimum-in-cart.input.json

```json
{
  "buyerJourney": { "step": "CART_INTERACTION" },
  "cart": { "cost": { "subtotalAmount": { "amount": "420.0" } } },
  "presentmentCurrencyRate": "1.0",
  "validation": { "metafield": null }
}
```

### tests/below-minimum-in-cart.output.json

```json
{ "operations": [] }
```

### tests/converted-minimum-met.input.json

```json
{
  "buyerJourney": { "step": "CHECKOUT_INTERACTION" },
  "cart": { "cost": { "subtotalAmount": { "amount": "95.0" } } },
  "presentmentCurrencyRate": "0.031",
  "validation": { "metafield": { "jsonValue": { "minimumAmount": 3000 } } }
}
```

### tests/converted-minimum-met.output.json

```json
{ "operations": [] }
```

## Limits and edge cases

- The subtotal is before taxes and cart-level discounts, as Shopify defines cart.cost.subtotalAmount.
- The minimum is converted with presentmentCurrencyRate; with fixed local prices per market, the converted figure may not be a round number.
- Errors are skipped while the buyer journey step is CART_INTERACTION and returned at checkout interaction and completion.

## Questions

### How do I set a minimum order amount on Shopify?

Use a cart and checkout validation Function that compares the subtotal with your minimum and blocks checkout below it, as this example does.

### Will customers see the message on the cart page?

Not with this code; it waits until checkout so the cart stays usable. Remove the CART_INTERACTION check if you want the message on the cart as well.

### Can wholesale customers have a different minimum?

Yes. Add cart.buyerIdentity.purchasingCompany or a customer tag check to the input query and use a second amount for them.

## Shopify documentation

- [Cart and Checkout Validation Function API](https://shopify.dev/docs/api/functions/latest/cart-and-checkout-validation)

## Related

- [Activate a delivery, payment or validation Function](https://lintelagency.com/resources/graphql/register-function-customization)
- [Blocking a Shopify checkout that breaks your rules, with Cart and Checkout Validation](https://lintelagency.com/journal/shopify-checkout-validation)
- [Selling in many currencies from one Shopify store](https://lintelagency.com/journal/shopify-markets-multi-currency)
- [Minimum and maximum quantity per product](https://lintelagency.com/resources/shopify-functions/min-max-quantity-per-product)

License: MIT. Free to use in your own store and in client work.
