PunchOut
Magento PunchOut
Magento and Adobe Commerce have no PunchOut of their own: no endpoint for a setup request, no cXML or OCI cart and no order intake from a procurement system. They do have what a PunchOut session needs underneath: shared catalogs per company in Adobe Commerce B2B, a cart API and a purchase order payment method. We build the PunchOut side on your existing Magento store and run it.
What moves between the procurement system and Magento
A PunchOut connection on Magento has the same flows as on any store. Magento carries the catalog, the prices and the order; the PunchOut documents run in the integration next to it.
| Flow | Direction | Where it runs |
|---|---|---|
| Setup request and response | procurement system to the integration | outside Magento, in the integration |
| Sign-in as the buyer's company | integration to the storefront | a storefront controller with a one-time identifier |
| Shopping at contract prices | in the storefront | shared catalog (B2B) or customer group prices |
| Cart transfer | storefront to the procurement system, through the browser | a checkout replacement and the integration |
| Purchase order | procurement system to the integration to Magento | REST API, order with payment method purchaseorder |
| Confirmation, ship notice, invoice | Magento or your ERP to the procurement system | the integration, as cXML |
Facts on this page were checked against Adobe's Commerce documentation and the Magento source on October 3, 2026. The documents themselves are explained on cXML PunchOut and OCI PunchOut.
What Magento offers and what is built around it
| Need | What Magento has | What is built |
|---|---|---|
| Endpoint for a setup request | nothing | the integration receives and answers it |
| Sign-in without a form | customer tokens for the API only | a controller that turns the start URL into a storefront session |
| Prices per buying organization | custom shared catalogs (Adobe Commerce B2B); tier prices per customer group | the company or group per buyer, filled from the ERP |
| Display in a frame | X-Frame-Options: SAMEORIGIN by default |
redirect, or a frame-ancestors rule per buyer |
| Cart data | the quote, with sku, qty, name and price per item |
a checkout replacement that sends the cart to the integration |
| Cart in cXML or OCI | nothing | the integration builds the PunchOutOrderMessage or the NEW_ITEM form |
| Order with a PO number | payment method purchaseorder with po_number |
the integration maps the OrderRequest to it |
Signing the buyer in
The start URL in the setup response has to open the store with the buyer already signed in as their company. Magento's REST API issues customer tokens through POST /V1/integration/customer/token, valid for 1 hour by default, but a token authorizes API calls, not the storefront. The browser needs Magento's session cookie.
The integration therefore adds a storefront route. The setup request for customer 10432 arrives, the integration stores the session with its return URL and BuyerCookie, and returns a start URL with a one-time identifier. The route checks the identifier, signs in the customer that belongs to it and opens the catalog. A used or expired identifier opens nothing. Regular customers keep the normal login page; nothing changes for them.
Prices per buying organization
In Adobe Commerce B2B, prices per company come from shared catalogs. Adobe's documentation describes two kinds:
| Shared catalog | Who sees it | How many |
|---|---|---|
| Public | guests and signed-in customers without a company | one at a time |
| Custom | signed-in users of the companies assigned to it | as many as needed |
Customer 10432 is a company in Magento with a custom shared catalog that holds item 10482 at 9.60 USD where the list price is 12.50. When the Shared Catalog feature is on, it controls all category permissions, and the existing customer group permissions are ignored. Tier prices can be set per customer group or per shared catalog, so a quantity price for this buyer sits in the same catalog.
Without B2B the same result comes from one customer group per buying organization with tier prices for that group. A store with 40 PunchOut buyers then has 40 customer groups, each filled from the ERP's price agreements by the integration.
Session lifetime and frames
Magento's default cookie lifetime is 3,600 seconds, renewed on every request, so the session ends one hour after the buyer's last click. SAP Ariba keeps a PunchOut session open for six hours. When the buyer's PHP session ends inside that window, everything stored in it is gone, including the return URL and the BuyerCookie.
A buyer starts at 09:03, clicks for the last time at 09:20 and comes back from a 75-minute meeting at 10:35. The cookie expired at 09:20 + 60 minutes = 10:20; Ariba's session runs until 09:03 + 6 hours = 15:03. Because the integration keeps the PunchOut session in its own table, keyed to the one-time identifier and the Magento quote, the buyer signs in again through the same session and sends the cart to the right return URL.
Frames are the second point. Magento sends X-Frame-Options: SAMEORIGIN by default, set in app/etc/env.php. The ALLOW-FROM option is deprecated because the browsers Magento supports no longer honor it, and Adobe's documentation advises against running the storefront in a frame at all. The procurement system opens the store by redirect. For a buyer that only supports a frame, Magento's CSP module has a frame-ancestors directive that names the hosts allowed to embed the PunchOut pages; since 2.4.7, CSP runs in restrict mode by default only on payment pages and in report-only mode elsewhere, so the rule has to be set to enforce on these pages as well. A second obstacle sits in the session cookie: Magento sets it with SameSite=Lax by default, and a browser does not send a Lax cookie to a page framed by another site. Inside a frame on the buyer's procurement host the browser does not send the session cookie back, so the store does not keep the sign-in from one page to the next. The redirect avoids both problems.
From the Magento cart to the PunchOut cart
The checkout button is replaced by a transfer button in a PunchOut session. The integration reads the quote, here one line of the cart of Bakker Installatie B.V.:
{
"item_id": 7,
"sku": "10482",
"qty": 120,
"name": "Duplex receptacle 20 A, white",
"price": 9.6,
"product_type": "simple",
"quote_id": "4"
}
What the integration does with it:
priceis a decimal number, not cents. 9.6 is written as9.60in cXML and OCI; 120 x 9.60 = 1,152.00 for the line.skubecomesSupplierPartIDorNEW_ITEM-VENDORMAT. A Magento SKU can be 64 characters, OCI takes 40, so a longer SKU is caught before the cart is sent.namebecomesDescription; for OCI it has to fit 40 characters. This one has 29.- Magento has no unit code on a product.
UnitOfMeasureand the classification come from a product attribute, filled once per product.
The purchase order back into Magento
The OrderRequest arrives at the integration, which answers it and places the order through the REST API with the payment method purchaseorder. That method ships with Magento as an offline payment method and is inactive by default, so it is switched on for the store and limited to PunchOut customers.
OrderRequest |
Magento |
|---|---|
orderID 4500001234 |
paymentMethod.po_number |
buyer identity in From |
the customer of company 10432 |
ItemOut lines |
cart items by SKU, at the price from the cart |
ShipTo |
shipping address |
BillTo |
billing_address |
Adobe Commerce B2B has its own purchase orders: with Enable Purchase Orders on for a company, every order becomes a purchase order that runs through that company's approval rules. In PunchOut the approval already happened in the buyer's system. The integration places the order through the API, and the setting stays off for PunchOut companies, so the order is not approved twice. For PO 4500001234 that is 3 calls to add the lines, one for the shipping information and one for the payment information that carries the PO number and returns the Magento order ID.
When it goes wrong
| What happens | Cause | Handling |
|---|---|---|
| Blank frame in the procurement system | X-Frame-Options: SAMEORIGIN |
redirect, or frame-ancestors per buyer |
| Cart goes to the wrong place or nowhere | session data kept in the PHP session, expired after 3,600 seconds | PunchOut session in the integration's own table |
| List price 12.50 in the cart | the customer is not in the company of its shared catalog | company and catalog per buying organization |
| Cart refused for its unit | no unit attribute on the product | fixed unit code per product |
| Order waits for approval in Magento | Enable Purchase Orders on for a PunchOut company | setting off; order placed through the API |
| Order without a PO number | placed with another payment method | purchaseorder with po_number |
The same pieces on other platforms: Shopify, WooCommerce and BigCommerce. The Ariba session rules are on PunchOut for Ariba, and what a store needs in full is on the PunchOut hub. Tell us which procurement system your customer uses.
Frequently asked questions
Do I need Adobe Commerce for PunchOut, or does Magento Open Source work?
Both work for the session and the cart. Contract prices per company are easiest with Adobe Commerce B2B, where a custom shared catalog holds the prices for the companies assigned to it. Without B2B, prices per buyer come from customer groups with tier prices, one customer group per buying organization.
Can the procurement system show my Magento store in a frame?
Not with the default settings. Magento sends X-Frame-Options: SAMEORIGIN, set in app/etc/env.php, and the ALLOW-FROM option is deprecated. Adobe advises against running the storefront in a frame. The buyer's administrator opens the store by redirect; where a buyer only supports frames, the PunchOut pages get a frame-ancestors policy for that buyer's host.
Can I use the customer token of the REST API to sign the buyer in?
No. POST /V1/integration/customer/token gives a bearer token for API calls, valid for 1 hour by default, not a storefront session. The browser needs a session cookie, so the start URL leads to a controller that checks the one-time identifier and signs the customer in on the storefront.
Does B2B purchase order approval in Adobe Commerce get in the way?
It can. With Enable Purchase Orders on for a company, every order from that company becomes a Magento purchase order that runs through its approval rules. In PunchOut the approval happens in the buyer's procurement system, so the setting stays off for companies that buy through PunchOut, or the order from the OrderRequest is created through the API outside the storefront checkout.
How does the PO number get onto the Magento order?
Through the Purchase Order payment method, code purchaseorder, which ships with Magento and is inactive by default. The integration sets it with the po_number from the OrderRequest when it places the order through the cart's payment-information endpoint, so the number is stored with the order.
Tell us what you need
Tell us which systems you use and what needs to work better. We reply personally within one working day. We help you define the work, then agree the price and timing before you commit.
- You know the price and the timeline before you commit to anything
- We work out the connection that takes the work off your hands
- We handle the build, hosting, monitoring and maintenance
- Your team has less information to retype and fewer discrepancies to chase