Skip to content
SyncMyShop

PunchOut

WooCommerce PunchOut

WooCommerce has no PunchOut of its own and no contract prices per customer in its core: one regular and one sale price per product, no endpoint for a setup request and no purchase order payment method. The sign-in, the prices per buyer, the cart transfer and the order intake are built as a plugin and an integration around the store. We build them on your existing WooCommerce store and run the connection.

What moves between the procurement system and WooCommerce

A PunchOut connection on WooCommerce has the same flows as on any store. WooCommerce keeps the products, the stock and the orders; the PunchOut documents run in the integration.

Flow Direction Where it runs
Setup request and response procurement system to the integration outside WordPress, in the integration
Sign-in as the buyer integration to the storefront a plugin route that sets the WordPress auth cookie
Shopping at contract prices in the storefront the plugin sets the price per cart line
Cart transfer storefront to the procurement system, through the browser a checkout replacement and the integration
Purchase order procurement system to the integration to WooCommerce REST API v3, order with the PO number as meta data
Confirmation, ship notice, invoice WooCommerce or your ERP to the procurement system the integration, as cXML

Facts on this page were checked against the WooCommerce and WordPress developer documentation and source on October 3, 2026. The documents themselves are on cXML PunchOut and OCI PunchOut.

What WooCommerce offers and what is built around it

Need What WooCommerce has What is built
Endpoint for a setup request nothing the integration receives and answers it
Sign-in without a form wp_set_auth_cookie() in WordPress a plugin route that signs in the user of a one-time start URL
Prices per buying organization regular_price and sale_price per product contract price per cart line, from the integration's price table
Cart data Store API GET /wp-json/wc/store/v1/cart, prices in minor units 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 REST API v3 orders with meta_data; no PO payment method the integration maps the OrderRequest to it

Signing the buyer in

WordPress signs a user in with wp_set_auth_cookie(). Called with $remember false, the cookie is a browser session cookie, and WordPress still ends the login after two days or when the browser closes, whichever comes first. With $remember true it lasts 14 days by default. A PunchOut sign-in uses the first: the session ends with the browser, and a link copied from it opens nothing a week later.

The plugin adds one route. The setup request for customer 10432 arrives at the integration, which stores the session with its return URL and BuyerCookie and answers with a start URL that carries a one-time identifier. The route checks the identifier, calls wp_set_auth_cookie() for the WordPress user linked to that session and opens the catalog.

Which user is linked matters more on WooCommerce than elsewhere. A signed-in user's cart is saved in the user meta _woocommerce_persistent_cart_ and follows that user to every device. Ten buyers at one customer on one shared WordPress account fill one cart between them. The integration links each PunchOut session to its own user, created from the UserEmail or Contact in the setup request when the buyer sends one.

WooCommerce's own session lasts 7 days for a signed-in user and 2 days for a guest, set in WC_Session_Handler. That is longer than SAP Ariba's six-hour PunchOut session, so the cart does not disappear on the store side during a session.

Prices per buying organization

WooCommerce core has one regular_price and one sale_price per product and no customer groups. A contract price per buyer comes from outside the product. The integration keeps a price table per buying organization, filled from the ERP, and the plugin sets that price on each cart line of a PunchOut session:

Item List price in WooCommerce Customer 10432 Source
10482, duplex receptacle 12.50 9.60 price agreement in the ERP
Panelboard 100 A 165.00 149.00 price agreement in the ERP
Cable ties, pack of 100 4.20 3.75 price agreement in the ERP

The product pages and the catalog show the same prices in the session, so the buyer never sees 12.50 and then 9.60 in the cart. Product data itself is written through the REST API's batch endpoints, which take up to 100 objects per request by default: 4,000 products is 4,000 / 100 = 40 requests.

From the WooCommerce cart to the PunchOut cart

The checkout button is replaced by a transfer button in a PunchOut session. The plugin reads the cart from the Store API, which returns the cart of the current session. A line of the cart of Bakker Installatie B.V., shortened:

{
  "sku": "10482",
  "name": "Duplex receptacle 20 A, white",
  "quantity": 120,
  "prices": {
    "price": "960",
    "currency_code": "USD",
    "currency_minor_unit": 2
  },
  "totals": { "line_total": "115200", "line_total_tax": "0" }
}
A WooCommerce Store API cart item mapped to a cXML ItemIn The Store API gives sku, name, quantity and prices in minor units. The integration divides the price by 100, takes the currency code and adds the unit from a product meta field, because WooCommerce has no unit of its own. WooCommerce Store API cXML ItemIn sku 10482 name Duplex receptacle 20 A, white quantity 120 prices.price "960" prices.currency_minor_unit 2 prices.currency_code USD product meta: unit EA no unit field in WooCommerce SupplierPartID 10482 Description Duplex receptacle 20 A, white quantity 120 UnitPrice/Money 9.60 Money @currency USD UnitOfMeasure EA 960 / 10^2
One cart line from the Store API to cXML. Prices arrive as strings in minor units.
  1. Prices are strings in minor units. With currency_minor_unit 2, "960" is 960 / 10^2 = 9.60 and "115200" is 1,152.00. Check: 120 x 9.60 = 1,152.00.
  2. line_total excludes tax, which line_total_tax holds. The cXML Total excludes tax as well, so the line totals add up without correction: 1,152.00 + 298.00 + 18.75 = 1,468.75.
  3. sku becomes SupplierPartID or NEW_ITEM-VENDORMAT. A variation without its own SKU has no part number for the buyer and is held back with an error in the log.
  4. WooCommerce has no unit field. UnitOfMeasure and the classification come from product meta fields, filled once per product.

The Store API's rate limiting is off by default; when a store switches it on, it counts only POST requests, 25 per 10 seconds by default. Reading the cart is a GET and is not counted.

The purchase order back into WooCommerce

The OrderRequest arrives at the integration, which answers it and creates the order with POST /wp-json/wc/v3/orders. WooCommerce's built-in offline gateways, bank transfer (bacs), cheque and cash on delivery, carry no PO number. The order is created with set_paid false and the PO number goes into meta_data:

OrderRequest WooCommerce order
orderID 4500001234 meta_data, key for example _po_number
buyer identity in From customer_id of the user linked to customer 10432
ItemOut lines line_items with product_id or variation_id, quantity and the contract price
ShipTo shipping
BillTo billing
payment terms payment_method, for example bacs, with set_paid false

set_paid true would set the order to processing and reduce stock as if it were paid. A PunchOut order is on account, so the integration leaves it false and the order status follows the ERP. The reply to the procurement system comes from the integration's queue, not from WordPress, so a slow WordPress host does not turn into a timeout at the buyer.

When it goes wrong

What happens Cause Handling
Colleague's items in the cart one shared WordPress user, persistent cart in user meta one user per buyer or per session
List price 12.50 in the PunchOut cart the cart line was not repriced, for example from a cached page price set on the cart line, PunchOut pages not cached
Blank frame a security plugin or the host adds X-Frame-Options header removed for the PunchOut routes, or redirect
Prices 100 times too high in the cart "960" read as 960.00 divide by 10 to the power currency_minor_unit
Order marked paid and stock reduced set_paid true set_paid false for every PunchOut order
PO number missing on the order no field for it in WooCommerce order meta data, passed to the ERP

The same pieces on other platforms: Shopify, Magento and BigCommerce. What a store needs in full is on the PunchOut hub, and how amounts in minor units and tax travel between systems is on money, tax and rounding. Tell us which procurement system your customer uses.

Frequently asked questions

Is there a WooCommerce extension that adds PunchOut?

There are third-party plugins for it. WooCommerce itself has none, and a plugin still needs what this page lists: a setup endpoint, a session per buyer, contract prices, a cart in the buyer's format and an order intake. We build those to your buyers' setups and your ERP, as a plugin on your store and an integration next to it.

Can several buyers at one customer share a WooCommerce login?

Not safely. WooCommerce keeps the cart of a signed-in user in the user meta _woocommerce_persistent_cart_, so two colleagues on one account fill the same cart. The integration signs in one WordPress user per PunchOut session, or per person named in the setup request, never one shared account.

How do contract prices work without a B2B plugin?

The integration keeps the price agreements per buying organization, filled from the ERP, and a small plugin sets that price on each cart line of a PunchOut session. The product keeps its list price for everyone else. Customer 10432 sees item 10482 at 9.60; a regular visitor sees 12.50.

Can the procurement system show my WooCommerce store in a frame?

WordPress core sends X-Frame-Options: SAMEORIGIN on the login page only, not on storefront pages, so a framed store usually loads. A security plugin or the host can add the header to every page; the integration checks the live headers of the PunchOut pages before the first test with the buyer.

Where does the PO number go on a WooCommerce order?

WooCommerce has no field for it. The integration creates the order through POST /wp-json/wc/v3/orders and stores the orderID from the OrderRequest as order meta data, shown on the order screen and passed to the ERP 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

Suppliers, products, orders per day, a rough estimate is fine.

Or email directly: carsten@syncmyshop.com