---
id: inventory-validation
title: Inventory Validation and Reservation
hide_title: true
description: "Strategies for validating stock availability and reserving inventory during checkout"
---

import Tabs from "@theme/Tabs";
import TabItem from "@theme/TabItem";
import Ingress from "../../../src/components/ingress/ingress.react";

<Ingress title="Inventory validation and reservation">
  Choose how to validate stock and reserve inventory during checkout, so that
  you stop overselling without adding friction for the customer.
</Ingress>

This guide compares three strategies for validating stock availability and reserving inventory during the checkout process.

## Overview of approaches

There are three main approaches to handle inventory during checkout:

| Approach | When to Validate | Best For |
|----------|------------------|----------|
| **No Validation** | After payment | Digital products, low-traffic stores |
| **Pre-Payment Validation** | Before payment | Standard e-commerce, stock checking |
| **Advanced Validation** | Before payment, Failed payment | Complex rules, Inventory reservation, Gift cards |

## Comparison matrix

Choose the right approach based on your requirements:

| Criteria | No Validation | Pre-Payment Validation | Advanced Callbacks |
|----------|--------------|----------------------|-------------------|
| **Overselling Prevention** | ❌ None | ✅ Good | ✅ Excellent |
| **Checkout Speed** | ⚡ Fastest | 🐌 Slower (+10s max) | 🐌 Slower (+10s max) |
| **Implementation Complexity** | ✅ Simple | ✅ Simple | ⚠️ Medium |
| **Conversion Rate Impact** | ✅ None | ⚠️ Potential negative | ⚠️ Potential negative |
| **Custom Validation** | ❌ No | ⚠️ Limited | ✅ Full support |
| **Rollback Support** | N/A | ❌ No | ✅ Yes (PaymentFailed) |
| **HTTP Method** | N/A | GET | POST with body |

## Approach 1: No validation (notification only)

### Overview

The simplest approach relies solely on the [notification callback](/docs/checkout/notificationcallback) to process orders after payment completion. No pre-payment validation is performed.

### Configuration

```json
{
  "storeId": 123,
  "countryCode": "SE",
  "merchantTermsUri": "https://myshop.com/terms",
  "notificationUri": "https://api.myshop.com/notifications/{checkout.id}",
  "cart": {
    "items": [...]
  }
}
```

### When to use

- **Digital products** - No physical inventory to manage
- **Made-to-order products** - Items created after purchase
- **Low-traffic stores** - Minimal risk of simultaneous purchases
- **Services** - No stock limitations

### Pros and cons

✅ **Advantages:**
- Fastest checkout experience
- Simplest implementation
- No timeout concerns
- Highest conversion rate

❌ **Disadvantages:**
- Risk of overselling
- Customer disappointment if items unavailable
- Manual handling of out-of-stock situations

### How it works

1. Customer completes payment through Walley Checkout
2. Walley sends GET request to your `notificationUri`
3. Your backend receives the notification
4. Check if order was already processed (idempotency)
5. Retrieve checkout information using the checkout ID
6. If status is `PurchaseCompleted`:
   - Deduct inventory from stock
   - Create the order in your system
   - Send confirmation email to customer
7. Respond with `200 OK` to confirm receipt

---

## Approach 2: Pre-payment validation

### Overview

Validate stock availability just before payment is processed using the `validationUri`. This provides a final check to ensure items are in stock before the customer's payment is authorized.

### Architecture

```
Customer completes checkout form
    ↓
Customer clicks "Complete Purchase"
    ↓
Walley calls validationUri (GET)
    ↓
Your backend checks stock availability
    ↓
Response: Success or Error
    ↓
If success → Process payment
    ↓
If payment succeeds → Notification callback
```

### Configuration

```json
{
  "storeId": 123,
  "countryCode": "SE",
  "merchantTermsUri": "https://myshop.com/terms",
  "notificationUri": "https://api.myshop.com/notifications/{checkout.id}",
  "validationUri": "https://api.myshop.com/validate/{checkout.id}",
  "cart": {
    "items": [...]
  }
}
```

### When to use

- **Standard e-commerce** - Typical online stores with inventory management
- **Medium traffic** - Moderate number of concurrent users
- **Simple validation** - Primary need is stock availability checking
- **Quick implementation** - Simpler than reservation systems

### Pros and cons

✅ **Advantages:**
- Prevents overselling at point of payment
- No reservation state to manage
- Simple to implement
- Works with existing inventory systems

❌ **Disadvantages:**
- Adds latency to checkout (up to 10 seconds)
- No rollback mechanism if payment fails
- Customer may lose item during checkout
- Multiple validation calls possible

### How it works

1. Customer completes checkout form and clicks "Complete Purchase"
2. Walley calls your `validationUri` with a GET request
3. Your validation endpoint:
   - Retrieves checkout information using the checkout ID
   - Checks stock availability for all items
   - Returns success (200 OK) or error (400/500) response
4. If validation succeeds:
   - Payment is processed
   - Order can optionally be created in pending state
5. If validation fails:
   - Customer sees error message
   - Purchase is not completed
6. After successful payment:
   - Walley sends notification to `notificationUri`
   - Your backend finalizes the order
   - Inventory is deducted
   - Confirmation email is sent

### Key considerations

- **10-Second Timeout**: Validation must complete within 10 seconds
- **Multiple Calls**: Validation may be called multiple times if customer retries
- **Idempotency**: Handle duplicate validation requests gracefully
- **Error Messages**: Provide clear feedback about unavailable items

:::warning Important
Even if validation succeeds, the purchase may still fail due to credit checks or payment issues. Always treat the order as pending until receiving the `notificationUri` callback with `PurchaseCompleted` status.
:::

---

## Approach 3: Advanced validation with callbacks

### Overview

Use the [callback object](/docs/checkout/optional/init-checkout-features#callback-object) with `ValidateOrder` and `PaymentFailed` callback types for advanced validation scenarios with built-in rollback support.

### Configuration

```json
{
  "storeId": 123,
  "countryCode": "SE",
  "merchantTermsUri": "https://myshop.com/terms",
  "notificationUri": "https://api.myshop.com/notifications/{checkout.id}",
  "callback": {
    "callbackUri": "https://api.myshop.com/callbacks/{checkout.id}",
    "callbackTypes": ["ValidateOrder", "PaymentFailed"]
  },
  "cart": {
    "items": [...]
  }
}
```

### When to use

- **Complex validation rules** - Multiple checks beyond stock (customer eligibility, regional restrictions)
- **Rollback requirements** - Need to handle payment failures gracefully
- **Multiple validation steps** - Customer verification, business rules, inventory reservation, gift cards

### Pros and cons

✅ **Advantages:**
- Prevents overselling
- Supports complex business logic
- Built-in rollback via PaymentFailed callback
- Structured request/response format

❌ **Disadvantages:**
- Adds latency to checkout (up to 10 seconds)
- More complex than validationUri
- Requires fast backend response
- May lower conversion rate if slow

### Callback flow

```
Customer completes checkout form
    ↓
Customer clicks "Complete Purchase"
    ↓
Walley calls ValidateOrder callback (POST)
    ↓
Your backend: Check stock, validate rules
    ↓
Response: Success or Error
    ↓
If success → Process payment
    ↓
If payment fails → PaymentFailed callback
    ↓
If payment succeeds → Notification callback
```

### How it works

**ValidateOrder Callback:**
1. Walley sends POST request to your `callbackUri` with type `ValidateOrder`
2. Request body includes `checkoutId` and `publicToken` for verification
3. Your backend:
   - Retrieves checkout information
   - Checks stock availability
   - Validates customer eligibility (if needed)
   - Validates business rules (regional restrictions, etc.)
   - Optionally reserves inventory
   - Creates pending order
4. Response options:
   - **Success (200 OK)**: Return `{ orderReference: "ORDER-123" }` (optional)
   - **Error (400)**: Return `{ title: "...", message: "...", clientPayload: {...} }`
   - **Timeout/Error (500)**: Customer sees generic error
<br/>
**PaymentFailed Callback:**
1. Triggered when payment fails after successful validation
2. Your backend:
   - Finds the pending order by checkoutId
   - Cancels the order
   - Releases any inventory reservations
   - Cleans up any other resources
3. Always respond with 200 OK (failures here don't affect customer)
<br/>
**Notification Callback:**
1. Triggered when payment succeeds
2. Your backend:
   - Updates order from pending to completed
   - Confirms inventory reservation (converts to sale)
   - Sends confirmation email
   - Triggers fulfillment process

### Key considerations

- **10-Second Timeout**: Validation must complete within 10 seconds
- **Idempotency**: Implement caching to handle duplicate calls
- **Error Handling**: Provide clear error messages to customers
- **Rollback**: Always handle PaymentFailed to release reservations

---



## Decision guide

Use this flowchart to choose the right approach:

```
Do you sell physical products with limited stock?
│
├─ NO (digital/services) → Use No Validation
│
└─ YES → Need to prevent overselling?
    │
    ├─ Simple stock checking only?
    │   └─ YES → Use Pre-Payment Validation (validationUri)
    │
    ├─ Need rollback if payment fails?
    │   └─ YES → Use Advanced Callbacks (ValidateOrder + PaymentFailed)
    │
    └─ Complex validation rules?
        (customer eligibility, regional restrictions, gift cards, release inventory reservations)
        └─ YES → Use Advanced Callbacks
```

## Migration from validationUri to callbacks

If you're currently using `validationUri` and want to add rollback support, migrate to the callback object:

**Before (validationUri):**
```json
{
  "notificationUri": "https://api.myshop.com/notifications/{checkout.id}",
  "validationUri": "https://api.myshop.com/validate/{checkout.id}"
}
```

**After (callback object):**
```json
{
  "notificationUri": "https://api.myshop.com/notifications/{checkout.id}",
  "callback": {
    "callbackUri": "https://api.myshop.com/callbacks/{checkout.id}",
    "callbackTypes": ["ValidateOrder", "PaymentFailed"]
  }
}
```

**Key Differences:**
- **Request Method**: GET (validationUri) → POST (callback)
- **Request Body**: None → JSON with type and checkout details
- **Rollback**: Not available → PaymentFailed callback
- **Authentication**: None → checkoutId and publicToken provided

:::tip
You cannot use both `validationUri` and `callback.ValidateOrder` simultaneously. Choose one validation method.
:::

## Best practices

### All approaches

- **Implement Idempotency**: Always check if a notification/callback was already processed
- **Comprehensive Logging**: Log all inventory operations for debugging and auditing
- **Monitor Performance**: Track validation times and reservation expiry rates
- **Error Handling**: Gracefully handle timeouts, connection failures, and partial stock

### Pre-payment validation (validationUri)

- **Response Time**: Must complete within 10 seconds
- **Idempotency**: Handle duplicate validation requests (customer may retry)
- **Error Messages**: Provide clear, specific reasons for validation failures
- **Pending Orders**: Optionally create pending orders during validation

### Advanced validation (callbacks)

- **Response Time**: Must complete within 10 seconds (set internal timeout at 8-9 seconds)
- **Optimization**: Use caching, batch queries, and parallel execution
- **Clear Errors**: Provide specific, actionable error messages to customers
- **Always Rollback**: Handle PaymentFailed callback to release resources

## Testing considerations

### Key test scenarios

1. **Happy Path**: Successful purchase with stock available
2. **Out of Stock**: Item becomes unavailable during checkout
3. **Reservation Expiry**: User abandons checkout, reservation is released
4. **Payment Failure**: Payment declined, rollback occurs correctly
5. **Concurrent Purchases**: Multiple users buying last available item
6. **Timeout Handling**: Validation takes too long, proper error shown

### What to verify

- Inventory is correctly reserved/deducted
- No overselling occurs under concurrent load
- Expired reservations are released
- PaymentFailed callback releases resources
- Idempotency works for duplicate notifications
- Error messages are clear and helpful

## Troubleshooting

| Issue | Possible Cause | Solution |
|-------|---------------|----------|
| Overselling occurs | Race conditions | Implement database locks/transactions |
| "Reservation expired" | Checkout takes too long | Increase expiry duration (30 min) |
| "Validation timeout" | Slow backend | Optimize queries, add caching |
| Inventory remains locked | Cleanup job not running | Verify background job is active |
| Duplicate orders | Missing idempotency | Always check if already processed |

## Related documentation

- [Initialize Checkout](/docs/checkout/initcheckout) - Setup callbacks and configuration
- [Validate Order Callback](/docs/checkout/optional/validateorder) - Detailed callback documentation
- [Notification Callback](/docs/checkout/notificationcallback) - Purchase completion handling
- [Gift Cards Use Case](/docs/checkout/common-use-cases/giftcards) - Another callback example

## Summary

Choose your inventory validation strategy based on:

- **Product type** - Digital → No Validation
- **Validation needs** - Simple stock check → Pre-Payment Validation
- **Rollback requirements** - Need cleanup → Advanced Callbacks
- **Business rules** - Complex logic → Advanced Callbacks

Remember that the [notification callback](/docs/checkout/notificationcallback) is **always required** and is the only reliable confirmation of purchase completion, regardless of which validation approach you choose.

For questions or assistance, contact Walley Merchant Services at [help@walley.se](mailto:help@walley.se).
