Understanding recurring order lists at a technical level
Requisition Lists are the B2B tool for repeat customers who regularly order the same line items, with their own data model, their own API, and a clear functional distinction from wishlists. Building a custom frontend integration means knowing how the data model is structured, which API operations are available, and where the default feature reaches its limits.
Table of Contents
- 1. Placing Requisition Lists in the B2B module
- 2. The data model: requisition_list and requisition_list_item
- 3. Requisition List vs. wishlist: the functional difference
- 4. API access for custom frontend integrations
- 5. Adding custom quantity rules via plugin
- 6. Typical use cases for repeat customers
- 7. Permissions: no team sharing out of the box
- 8. Performance with large lists
- 9. Maintaining stale lists
- 10. Summary
- 11. FAQ
1. Placing Requisition Lists in the B2B module
Requisition Lists are part of the Magento_RequisitionList module from the B2B Suite and solve a very concrete problem: company customers frequently order the same or very similar line items again and again, such as consumables or spare parts, and do not want to search the catalog from scratch every time. At its core, a Requisition List is a named, reusable collection of SKUs with fixed quantities attached, which can be pulled into the cart in full or in part.
Unlike many other B2B features, a Requisition List is not tied to a company but to the individual customer. Two employees of the same company therefore do not see the same lists by default, even when connected through the same company, which is a relevant design decision for many projects once shared order templates within a team come into play.
2. The data model: requisition_list and requisition_list_item
Technically a Requisition List consists of two tables: requisition_list with the fields requisition_list_id, customer_id, name, and description, and requisition_list_item with sku, qty, requisition_list_id as a foreign key, and a serialized additional_options field for product options such as configurable attributes or custom text fields. The actual product reference is made through the SKU, not the internal product ID, which matters when SKUs change in the catalog.
Because additional_options is stored serialized, a saved item cannot simply be filtered by a specific product option through a plain SQL filter. For custom reporting, such as a report on the most frequently stored configurations across lists, the serialized data first has to be deserialized through the corresponding serializer classes before it can be analyzed in a structured way.
3. Requisition List vs. wishlist: the functional difference
At first glance, Requisition Lists and wishlists look similar; both store a named list of products for a customer. The key difference is purpose: a wishlist is built for saving and potentially sharing, with optional comments and a sharing function through a public link. A Requisition List, in contrast, has a purely operational purpose: fast, repeated ordering with a fixed quantity stored per line item.
In practice this shows up in the available actions. Requisition Lists allow adding the entire list to the cart, including quantity adjustments, in a single step, while a wishlist is geared more toward adding individual products one at a time. A Requisition List also does not support public visibility or sharing with other users out of the box; it stays strictly bound to the customer who created it.
4. API access for custom frontend integrations
For custom frontends, both service contracts like RequisitionListRepositoryInterface and RequisitionListItemRepositoryInterface, and a GraphQL layer, are available. The requisitionLists GraphQL query returns a logged-in customer's lists including their items, while mutations such as createRequisitionList and addProductsToRequisitionList handle creation and populating them.
For the actual ordering step, the addRequisitionListToCart mutation matters, validating either the full list or a selected subset of items and moving them into the active cart. Validation runs per item separately, so a single faulty item, for example a product that has since been disabled, does not necessarily block the entire action but is reported back as an individual error in the result.
mutation AddRequisitionListToCart {
addRequisitionListToCart(
cartId: "abc123cartid"
requisitionListId: "42"
requisitionListItemIds: ["101", "102", "103"]
) {
cart {
id
total_quantity
}
userErrors {
requisition_list_item_id
message
code
}
}
}
5. Adding custom quantity rules via plugin
A common extension case is an additional quantity validation, for example when a product may only be ordered in multiples of a pack size. A plugin on RequisitionListItemRepositoryInterface::save is the right fit, checking before the actual save whether the stored quantity matches the product's configured pack size, and throwing a LocalizedException otherwise.
This check should consistently apply at the same point where the item later gets added to the cart, since otherwise invalid quantities, while not stored in the list, could still be ordered through another path such as direct product detail page access. A consistent rule therefore belongs in a central, reusable validator rather than in a single isolated plugin.
<?php
declare(strict_types=1);
namespace Mironsoft\RequisitionListExtension\Plugin;
use Magento\Framework\Exception\LocalizedException;
use Magento\RequisitionList\Api\Data\RequisitionListItemInterface;
use Magento\RequisitionList\Api\RequisitionListItemRepositoryInterface;
use Mironsoft\RequisitionListExtension\Model\PackSizeValidator;
/**
* Ensures quantities on requisition list items are a multiple of the
* product's configured pack size.
*/
class ValidatePackSizePlugin
{
/**
* @param PackSizeValidator $packSizeValidator
*/
public function __construct(private readonly PackSizeValidator $packSizeValidator)
{
}
/**
* @param RequisitionListItemRepositoryInterface $subject
* @param RequisitionListItemInterface $item
* @return array{RequisitionListItemInterface}
* @throws LocalizedException
*/
public function beforeSave(
RequisitionListItemRepositoryInterface $subject,
RequisitionListItemInterface $item,
): array {
if (!$this->packSizeValidator->isValidQty($item->getSku(), (float) $item->getQty())) {
throw new LocalizedException(__('Quantity must be a multiple of the pack size.'));
}
return [$item];
}
}
6. Typical use cases for repeat customers
In practice, Requisition Lists pay off most where orders occur regularly and predictably. A classic example is maintenance teams ordering the same spare parts for a given machine every month, or branch locations regularly reordering a standardized set of consumables in fixed quantities, without having to gather the right products from scratch every time.
Another common use case is quickly repeating a previous order: instead of manually duplicating a past order, the customer creates the relevant items as a Requisition List once and only adjusts quantities on each subsequent order, which noticeably speeds up the ordering process and reduces SKU typos that are more likely when searching the catalog manually.
7. Permissions: no team sharing out of the box
An important limitation that is often overlooked when planning custom extensions: Requisition Lists are strictly bound to the creating customer in the default feature set and are not automatically visible to other members of the same company. Anyone wanting a shared order template across a team has to add that functionality explicitly, for example through an extra visibility attribute at the company level and a correspondingly extended repository query.
For such an extension, it makes sense to add a visibility column to the existing requisition_list table and extend the default collection with an additional filter through a plugin, rather than replacing the entire repository implementation. That keeps compatibility with future Magento updates and the existing GraphQL layer largely intact.
8. Performance with large lists
For lists with several hundred items, validation when adding to cart noticeably affects response time, because price, availability, and configuration options are checked individually for every item. For very large lists, it is worth calling addRequisitionListToCart in smaller batches instead of the full list at once, to limit both response time and the risk of a timeout with slow external price sources.
For recurring, plannable use, such as an automated nightly conversion of certain requisition lists into orders through an external procurement system, it is also worth reusing the same validation path as the frontend rather than implementing separate, diverging logic, so frontend and automation behavior do not drift apart over time.
9. Maintaining stale lists
Since Requisition Lists persist indefinitely and do not expire automatically, lists accumulate over the years that contain items referencing products that have since been disabled or discontinued. Without custom maintenance, such orphaned entries persist indefinitely and lead to validation errors when the list is added to the cart, errors that are hard for the customer to understand without context.
A worthwhile addition is a regular batch job that identifies items referencing SKUs that no longer exist or are permanently disabled, and either removes them automatically or flags them for the customer on next login as stale, so the list retains its practical value as a reliable order template.
| Feature | Wishlist | Requisition List |
|---|---|---|
| Primary purpose | Saving and sharing | Fast, repeated ordering |
| Team sharing | Public link possible | Not without custom extension |
| Quantity per item | Usually 1, editable | Fixed, meant for reordering |
| Full cart transfer | Not built in by default | Through addRequisitionListToCart |
| Ownership | Bound to the customer | Bound to the customer, not the company |
| Typical user | End customer in a B2C context | Company customer with recurring demand |
Mironsoft
Magento development, module consulting, and system architecture
A Magento project that needs a second opinion or experienced execution?
We build custom Magento modules, advise on architecture decisions, and take on complex implementations, from service contract planning to production-ready deployment.
Architecture Consulting
Have module and system architecture thought through properly before you build.
Custom Module Development
Build custom Magento modules cleanly, following best practices.
Code Review & Audit
Have existing modules reviewed for performance, security, and maintainability.
10. Summary
Requisition Lists
Data model
requisition_list and requisition_list_item store name, customer, SKU, quantity, and serialized product options.
Distinction
Unlike the wishlist, the Requisition List is built for fast reordering rather than saving and sharing.
API
GraphQL mutations such as addRequisitionListToCart validate every item individually and report errors granularly.
Limits
No team sharing out of the box, no automatic cleanup of stale items without a custom extension.