Notes
What is a PunchOutSetupRequest?
A PunchOutSetupRequest is the cXML document a procurement system posts to a supplier's endpoint when a buyer clicks the supplier's catalog. It says who the buyer is, what kind of session to open and where the cart has to go back to, and the endpoint answers with a status and a one-time start URL.
Updated
What the setup request does
When a buyer at Bakker Installatie B.V. clicks your tile in the procurement system, the system posts a PunchOutSetupRequest to your endpoint over HTTPS. Your endpoint answers in the same connection with a PunchOutSetupResponse that holds a status and a start URL, and the procurement system sends the buyer's browser to that URL. Every fact on this page comes from the cXML Reference Guide 1.2.071 and its DTD, checked on October 3, 2026, unless a procurement system is named.
The request has three jobs:
| Job | Where in the document |
|---|---|
| Prove who is calling | Header: From, To, Sender with the SharedSecret |
| Say what kind of session | the operation attribute: create, edit, inspect or source |
| Say where the cart goes back to | BrowserFormPost/URL, plus BuyerCookie to match the cart to this session |
Everything else, the user's name, a cost center, a delivery address, a product the buyer already picked, is optional and differs per procurement system.
The document, annotated
This is an edit request: the buyer reopens the cart of 3 lines sent earlier, to change a quantity.
<cXML payloadID="1791032780.2210.55012@procure.bakker.example"
timestamp="2026-10-03T10:12:40-04:00">
<Header>
<From><Credential domain="NetworkId"><Identity>bakker-installatie</Identity></Credential></From>
<To><Credential domain="NetworkId"><Identity>your-store</Identity></Credential></To>
<Sender><Credential domain="NetworkId"><Identity>bakker-installatie</Identity>
<SharedSecret>the-agreed-secret</SharedSecret></Credential></Sender>
</Header>
<Request deploymentMode="production">
<PunchOutSetupRequest operation="edit">
<BuyerCookie>7QW2M0D41KXA</BuyerCookie>
<Extrinsic name="UserEmail">j.devries@bakker.example</Extrinsic>
<BrowserFormPost><URL>https://procure.bakker.example/return</URL></BrowserFormPost>
<ItemOut quantity="120"><ItemID><SupplierPartID>10482</SupplierPartID>
<SupplierPartAuxiliaryID>cart-88231</SupplierPartAuxiliaryID></ItemID></ItemOut>
<!-- two more ItemOut lines: 2 x panelboard, 5 x cable ties -->
</PunchOutSetupRequest>
</Request>
</cXML>
The payloadID is unique per document and stays the same if the request is sent again. The timestamp is ISO 8601 with a UTC offset. deploymentMode is test or production, and production is the default when it is absent. The full envelope is explained on cXML PunchOut.
Element by element
The DTD fixes the order of the body: BuyerCookie, then Extrinsic*, BrowserFormPost?, Contact*, SupplierSetup?, ShipTo?, SelectedItem?, ItemOut*. A * means zero or more, a ? zero or one.
| Element | Required | What it holds | What the endpoint does |
|---|---|---|---|
BuyerCookie |
yes | an opaque value from the procurement system | stores it, returns it unchanged in the cart |
Extrinsic |
no | named values: UserEmail, UniqueName, CostCenter |
uses them when present, never depends on them |
BrowserFormPost |
no | the URL the cart is posted to |
stores it with the session |
Contact |
no | name, email, role such as endUser |
identifies the person, for example to pick a user account |
SupplierSetup |
no | the URL of your PunchOut site; deprecated since cXML 1.1 | ignores it; the network or the buyer already knows the URL |
ShipTo |
no | an address for delivery and price estimates | may use it for prices; the order's address is the one that counts |
SelectedItem |
no | the ItemID of a product picked in the buyer's own search |
opens that product; see Level 2 PunchOut |
ItemOut |
no | the lines of an earlier cart on edit and inspect |
rebuilds the cart from them |
The reference says the endpoint can use From to identify the company and Contact and the extrinsics to identify the person, and that buying organizations configure which of those they send. Its advice is to ask each customer what to expect.
Who the user is
What arrives about the person differs per procurement system:
| System | What it sends about the user |
|---|---|
| Coupa | extrinsics FirstName, LastName, UniqueName, UserEmail, User, BusinessUnit, and Contact role="endUser" in its published sample |
| SAP Ariba, Ariba Buyer 7.0 and later | the Contact element, which replaced the User and CostCenter extrinsics of version 6.1 and earlier |
| The cXML reference's own sample | UserEmail, UniqueName, CostCenter |
An endpoint that requires UserEmail fails the first buyer whose administrator did not configure it. SAP's guide for suppliers on SAP Business Network adds that required extrinsics lengthen the implementation and should be kept to a minimum. The store therefore opens the session on the company from From alone, and uses the person's data when it is there, for example to give each buyer their own cart.
The BuyerCookie is not a session key
The reference says the BuyerCookie is unique per PunchOut session and changes from create to inspect to edit, and that a store should not use it to track sessions. Two systems bend that:
- Coupa creates one
BuyerCookieper user and PunchOut site and never changes it, as described on PunchOut for Coupa. - Through SAP Business Network, a request from Ariba Buyer 7.0 arrives with a session ID number in place of the value the buyer's system generated.
A store that keys its sessions on the BuyerCookie mixes up two sessions of the same Coupa user. The endpoint creates its own session identifier, stores the BuyerCookie next to it, and returns the cookie only in the cart.
Worked example: rebuilding a cart on edit
The edit request above carries the 3 lines of the original cart. The endpoint matches each SupplierPartAuxiliaryID to the stored cart cart-88231 and rebuilds it at today's contract price:
| Item | Quantity | Price then, now | Line now |
|---|---|---|---|
| 10482 receptacle | 120 | 9.60, 9.85 | 1,182.00 |
| panelboard | 2 | 149.00, 149.00 | 298.00 |
| cable ties, pack | 5 | 3.75, 3.75 | 18.75 |
The original total was 120 x 9.60 + 298.00 + 18.75 = 1,468.75. With the receptacle at 9.85 the rebuilt cart is 1,182.00 + 298.00 + 18.75 = 1,498.75, 30.00 more. The difference shows in the cart the buyer sends back, so it is visible before approval. The reverse, keeping 9.60 because the cart was created at that price, is a rule per buyer agreement and is stored with the session. An endpoint that does not support edit answers 450 Not Implemented, and Coupa, which sends only create and inspect, never asks for it.
What the response has to contain
| Status | When | Body |
|---|---|---|
| 200 OK | accepted | PunchOutSetupResponse with StartPage/URL |
| 401 Unauthorized | the shared secret does not match | status only |
| 406 Not Acceptable | the XML does not validate | status only |
| 450 Not Implemented | the operation is not supported | status only |
| 500 Internal Server Error | the request could not be completed | status only; the buyer may retry |
The reference asks for a start URL that refers to the session state instead of carrying it, because many applications limit URL length. A short identifier such as ?sid=9f2c41d8a07b that works once and expires fast does that, and a copied link then opens nothing.
What this means for your integration
A setup endpoint has to accept documents that differ per procurement system, identify the company without depending on optional fields, keep its own session key and answer with a start URL that signs the buyer in.
We build the endpoint on your existing store, keep the per-buyer rules (credentials, extrinsics, price on edit) in the integration and log every setup request with its response. The whole PunchOut flow, from setup request to invoice, is on the PunchOut hub. Send us a sample setup request from your customer.
Frequently asked questions
Is the PunchOutSetupRequest the same as the purchase order?
No. The setup request opens a shopping session and carries no order. The cart comes back as a PunchOutOrderMessage, the buyer's system turns it into a requisition, and only after approval does the purchase order arrive, as a separate OrderRequest document.
Which elements of a PunchOutSetupRequest are required?
In the cXML DTD only BuyerCookie and the operation attribute. Extrinsic, BrowserFormPost, Contact, SupplierSetup, ShipTo, SelectedItem and ItemOut are optional. In practice every procurement system sends BrowserFormPost, because without it the store has nowhere to post the cart.
Why does my endpoint answer 401 to a correct shared secret?
Usually because it looks up the customer by the identity in Sender. When the request comes through a network such as SAP Business Network, Sender holds the network's identity and your own shared secret, not the buyer's. Check the secret in Sender and find the customer by From.
Can I test a PunchOutSetupRequest without the buyer?
Yes. Post a sample document like the one on this page to your endpoint with deploymentMode="test" and check the response: status 200 and a start URL that opens the right catalog once and then expires. The round trip with the cart and the return URL needs the buyer's test system.
Which cXML version should the endpoint accept?
The one the buyer sends, named in the DOCTYPE line. Coupa sends the setup request in DTD 1.2.014; the current reference is 1.2.071. The elements on this page exist in both, so an endpoint that reads them and passes over unknown elements handles either.
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