cXML punchout, end to end

The documents of a punchout session and the purchase order that follows, what each field is for, and how the round trip maps onto a Shopify B2B store.

Published
Referenced documents
3

cXML punchout lets a procurement system open a supplier's web store in a live session. The buyer's system posts a PunchOutSetupRequest, the supplier answers with a start page URL, the user shops, and the cart returns as a PunchOutOrderMessage through the user's browser. After approval, the purchase order arrives separately as an OrderRequest.

This page follows one round trip from the integrator's side, citing the cXML User's Guide (version 1.2.037) by section. The XML excerpts come from the samples on the cXML punchout messages reference, which has each document in full with its status codes. If you want the business view first, read what a punchout catalog is or how punchout works.

Which documents make up a cXML punchout?

A punchout site has to support four transactions: Profile, PunchOutSetupRequest, PunchOutSetupResponse and PunchOutOrderMessage (guide, section 5.1.2.2). The purchase order is a separate capability: an OrderRequest sent to an order URL, answered with a plain cXML Response (sections 7.1 and 7.3).

DocumentSent bySent toTransport
ProfileRequest / ProfileResponseNetwork or buyer systemSupplierHTTPS POST, answered in the same connection
PunchOutSetupRequest / PunchOutSetupResponseBuyer system, often through a networkSupplier setup URLHTTPS POST, answered in the same connection
PunchOutOrderMessageSupplier siteBuyer systemHTML form posted by the user's browser
OrderRequest / ResponseBuyer system or networkSupplier order URLHTTPS POST, answered in the same connection

The Profile transaction is how a network learns your URLs. SAP Business Network sends a ProfileRequest and routes punchout requests to the setup URL your ProfileResponse lists, or to the URL entered in your account (SAP catalog format reference). PunchRelay answers ProfileRequest on both its setup URL and its order URL.

PunchRelay connects your Shopify B2B store to your buyers' procurement systems: contract prices go out in the punchout catalog, and purchase orders come back to your inbox for review.

Install on ShopifyWatch the 78-second demo

30-day free trial, billed through Shopify

What does the buyer's system send in the PunchOutSetupRequest?

A header that says who is asking and proves it, and a body that says what kind of session to open. The header carries From, To and Sender credentials, with the shared secret in Sender. The body carries the BuyerCookie, the BrowserFormPost URL for the cart, optional extrinsic data and the operation.

<Header>
  <From>
    <Credential domain="NetworkID">
      <Identity>AN01000012345-T</Identity>
    </Credential>
  </From>
  <To>
    <Credential domain="NetworkID">
      <Identity>AN02000067890</Identity>
    </Credential>
  </To>
  <Sender>
    <Credential domain="NetworkID">
      <Identity>AN01000012345-T</Identity>
      <SharedSecret>the-secret-you-issued</SharedSecret>
    </Credential>
    <UserAgent>Procurement Suite 2026</UserAgent>
  </Sender>
</Header>

From is the buying organization and To is the supplier. Sender is whoever transmits the document; intermediate nodes such as a network change it on the way, while From and To stay the same (section 5.3.2). When a network relays the request, it checks the buyer's own secret, then inserts the supplier's shared secret into Sender, so the supplier knows the request is authentic because it carries the supplier's own secret (section 5.3.2.2). Where the buyer configures the supplier in their own system, the request carries the shared secret the supplier gave them; Coupa lists it as a required credential.

  • operation: create opens a new cart, edit reopens an earlier cart for changes, inspect reopens it read-only, and source is for sourcing requests (section 5.3.2.1). For edit and inspect the request lists the earlier lines as ItemOut elements. Coupa's supplier documentation says it supports create and inspect only.
  • BuyerCookie: opaque to the supplier and unique per session. It must come back with the cart so the buyer's system can match it to the requisition, and it changes from create to inspect to edit, so it cannot track a cart across sessions (sections 5.3.4 and 5.6.2.3).
  • BrowserFormPost: the URL the cart is posted to at the end (section 5.6.2.4).
  • Extrinsic: name and value pairs the two sides agree on, often the user's email or cost center (section 5.6.2.5).
  • deploymentMode on Request: production (the default) or test (section 3.1.8).

PunchRelay authenticates the request by the From identity and the Sender shared secret, compared in constant time against every enabled connection with that identity. It accepts create, edit and inspect, and keeps the UserEmail extrinsic with the session.

What does the supplier answer?

In the same HTTP connection, a cXML Response with a Status and, on success, a StartPage URL. The buyer's system opens that URL in the user's browser. It has to bind to the session on the supplier side, and because many applications limit URL length, the guide has it refer to the session state instead of carrying all of it (sections 5.3.3 and 5.6.3.1).

PunchOutSetupResponse
<Response>
  <Status code="200" text="OK" xml:lang="en"/>
  <PunchOutSetupResponse>
    <StartPage>
      <URL>https://relay.example.com/catalog?token=one-time-token</URL>
    </StartPage>
  </PunchOutSetupResponse>
</Response>

The guide asks for a start page URL that is unique to the session and valid only for a limited time (section 5.4.1). cXML status codes come in ranges: 2xx is success, 4xx a permanent error the client should not retry, 5xx a transient error the client should retry, and a PunchOutSetupResponse belongs only in a 2xx answer (section 3.1.9.1). PunchRelay's start page token works once and expires after 15 minutes, which is why a start URL copied from a log will not open the catalog again. The punchout errors guide covers the failures you see during testing.

What happens while the user shops?

The user browses the supplier's site in an ordinary browser session, already logged in as the buyer. The start page logs the requester in, and the guide asks suppliers to admit only authorized users before showing anything, because confidential prices would otherwise be exposed (section 5.4.2). From there, the guide says, shopping is "the same as if they had logged on to the supplier's website directly" (section 5.2.2).

In PunchRelay the start page opens a catalog hosted by PunchRelay that reads your Shopify store. It shows the products Shopify publishes to the connection's company location, with the contract prices, quantity rules and volume breaks Shopify returns for that location, or list prices when the location has no catalog.

How does the cart get back to the procurement system?

Through the user's browser. The supplier's checkout page holds the PunchOutOrderMessage in a hidden form field and the browser posts it to the BrowserFormPost URL. The field is named cxml-urlencoded or cxml-base64, and buyers need no web server reachable through their firewall (section 5.4.3.1).

<PunchOutOrderMessage>
  <BuyerCookie>c41e-88f0-requisition-5521</BuyerCookie>
  <PunchOutOrderMessageHeader operationAllowed="edit">
    <Total><Money currency="EUR">187.20</Money></Total>
  </PunchOutOrderMessageHeader>
  <ItemIn quantity="8">
    <ItemID>
      <SupplierPartID>PAP-A4-80-5R</SupplierPartID>
      <SupplierPartAuxiliaryID>sess-9d2f</SupplierPartAuxiliaryID>
    </ItemID>
    <ItemDetail>
      <UnitPrice><Money currency="EUR">23.40</Money></UnitPrice>
      <Description xml:lang="en">Copy paper A4 80 g · Box of 5 reams</Description>
      <UnitOfMeasure>BX</UnitOfMeasure>
      <Classification domain="UNSPSC">14111507</Classification>
      <ManufacturerPartID>CP-A480-5</ManufacturerPartID>
      <ManufacturerName xml:lang="en">Example Paper Mill</ManufacturerName>
      <LeadTime>2</LeadTime>
    </ItemDetail>
  </ItemIn>
</PunchOutOrderMessage>
  • BuyerCookie is returned unchanged from the setup request.
  • Total in the header is the cost of the items, excluding tax and shipping (section 5.6.4.2).
  • operationAllowed sets what the buyer may do with these lines later: create allows no later session, inspect allows viewing, edit allows viewing and changing (section 5.6.4.2).
  • SupplierPartAuxiliaryID is the supplier's cookie. The buyer's system passes it back in later edit and inspect sessions and in the purchase order, and the supplier should not change it during those sessions (section 5.3.4).
  • UnitOfMeasure uses UN/CEFACT common codes, and Classification carries the UNSPSC code (sections 3.2.1 and 5.3.4).

A message without ItemIn lines is valid and means different things per operation: after inspect it changes nothing, after create it adds nothing, after edit it removes that session's lines from the requisition (section 5.6.4.3). Either way the guide is clear about what the cart is: "PunchOut transactions produce quotes, not purchase orders" (section 5.5.1).

PunchRelay posts cxml-urlencoded by default and lets you switch a connection to cxml-base64 when the buyer reads that one. It sends operationAllowed="edit", puts the session ID in SupplierPartAuxiliaryID, and creates nothing in Shopify at this step.

How does the purchase order arrive?

After the requisition is approved, the buyer's system turns it into a purchase order and posts an OrderRequest to the supplier's order URL, with the same kind of header and shared secret. The supplier answers with a Response whose status says the document was received and parsed (sections 5.2.4, 7.1 and 7.3).

<OrderRequestHeader orderID="4500018832" orderDate="2026-10-17T10:02:00+02:00"
                    type="new">
  <Total><Money currency="EUR">187.20</Money></Total>
  <ShipTo>
    <Address addressID="DC-NORTH">
      <Name xml:lang="en">Example Org, North warehouse</Name>
      <PostalAddress>
        <DeliverTo>Goods receipt, dock 3</DeliverTo>
        <Street>Industriestrasse 12</Street>
        <City>Hamburg</City>
        <PostalCode>20095</PostalCode>
        <Country isoCountryCode="DE">Germany</Country>
      </PostalAddress>
    </Address>
  </ShipTo>
</OrderRequestHeader>

orderID is the buyer's purchase order number and orderDate is required. type is new by default, or update or delete for change orders that refer back to the original. Total again excludes tax and shipping (section 7.2). Each ItemOut carries the SupplierPartAuxiliaryID from the cart, which is how the supplier connects the order to the punchout session. A status 200 means the request was parsed and acted on; it says nothing about which items ship or are backordered (section 7.3).

PunchRelay accepts type="new" and answers 200 once the purchase order is stored. It answers 450 to updates and deletions, and 409 when the same orderID arrives again with different content. It checks the order against the cart the buyer transferred and places it in the Purchase orders inbox.

How does cXML punchout map onto Shopify?

Each step of the round trip has a Shopify counterpart. The connection stands for one buyer and is tied to a Shopify company, location and contact; the catalog and prices come from that location; and the purchase order becomes a Shopify order only when someone on your team approves it.

cXML stepIn Shopify, with PunchRelay
From identity and shared secretA PunchRelay connection tied to one Shopify company, company location and contact
StartPage and shoppingProducts Shopify publishes to that company location, at its catalog prices, quantity rules and volume breaks
PunchOutOrderMessageSKUs, prices, units and UNSPSC codes from your products, their metafields or the connection's mappings; no Shopify order, draft order or payment
OrderRequestA purchase order in the Purchase orders inbox, checked against the transferred cart
Your approvalCreate Shopify order: an unpaid order for the company location, with the buyer's PO number

Approval checks the current contract price again. If a price, quantity rule or catalog changed after the transfer, PunchRelay reports a conflict instead of creating the order, and you settle it with the buyer.

What PunchRelay does, and what you and the buyer do

PunchRelay handles every document on this page for your store: it authenticates setup requests and purchase orders, serves the catalog, posts the cart back, and logs the documents with secrets redacted so both sides can read the same XML. A cXML connection needs no custom code.

A punchout session in the PunchRelay app: status Cart returned, the cart summary, and the document timeline with the setup request's raw cXML, the shared secret shown as [REDACTED].
A punchout session in the PunchRelay app: status Cart returned, the cart summary, and the document timeline with the setup request's raw cXML, the shared secret shown as [REDACTED].
ViewOne session in the PunchRelay app: every document is logged, with the shared secret redacted. Data from a test store.

You create the connection in the PunchRelay admin. You enter the buyer's identity (for SAP Ariba, their ANID), pick test or production mode, and PunchRelay generates the credentials, which are shown once. You send the buyer the setup URL, the order URL, the identity and the shared secret, keep your B2B data in Shopify, and review each purchase order. The buyer's team enters those details in their procurement system, tests the round trip with you and moves to production. The setup guide walks through it, and the SAP Ariba and Coupa pages cover those systems. If the buyer runs an SAP ERP instead, read OCI punchout.

Referenced documents

Ref.DocumentNotes
[1]cXML User's Guide, version 1.2.037 (cXML.org)Required punchout transactions (5.1.2.2), hub authentication (5.3.2.2), PunchOutSetupRequest elements and operations (5.3.2.1, 5.6.2), start page rules (5.4.1, 5.6.3.1), form encoding (5.4.3.1), operationAllowed and empty carts (5.6.4.2, 5.6.4.3), supplier cookie (5.3.4), status codes (3.1.9.1), deploymentMode (3.1.8), OrderRequestHeader (7.2) and the response to an OrderRequest (7.3).
[2]SAP Ariba Customer Catalog Format Reference, document version 2605SAP Business Network routes punchout requests to the setup URL from the supplier's ProfileResponse or account configuration.
[3]Coupa Compass: Punchout catalogs (supplier resources)Coupa's supported setup operations (create and inspect) and the shared secret as a required credential.

Install PunchRelay from the Shopify App Store

Start the 30-day free trial from the listing. Pricing is $349/month with two punchout connections included, billed through Shopify.

Talk to us about your buyer's system

Questions about your buyer's procurement system, or want help with setup? Leave your email and we will reply personally.

Install the app if you know which procurement system your buyer uses. If you don't know yet, talk to us first.

No spam. We reply personally.