PunchOut
Package: @propeller-commerce/propeller-v2-punchout
Many B2B buyers order through an e-procurement system, such as SAP Ariba, Coupa or an SAP system. With PunchOut, the buyer starts in that system, lands in your storefront already signed in, fills a cart and sends it back to their system as a requisition. The buyer's organization then approves and orders through its own process.
Checked against propeller-v2-punchout 0.1.0 and the boilerplates of 18 October 2026.
The two protocols
| OCI (SAP Open Catalog Interface) | cXML (Ariba, Coupa) | |
|---|---|---|
| Start | The procurement system opens your entry URL with a sign-in token | The procurement system posts a PunchOutSetupRequest, and your storefront answers with a start URL |
| Sign-in | The token in the entry URL | A one-time token, valid for an hour, created during the setup |
| Cart back | A form of NEW_ITEM-* fields posted to the system's HOOK_URL | A PunchOutOrderMessage posted to the system's return URL |
How it works
cXML: procurement system ── POST PunchOutSetupRequest ──▶ /api/punchout/cxml/setup
◀── PunchOutSetupResponse (start URL /api/punchout/enter) ──
OCI: procurement system ── opens /api/punchout/enter?mode=oci&mtoken=…&HOOK_URL=… ──▶
/api/punchout/enter stores the PunchOut session and signs the buyer in
the buyer shops
Transfer cart POST /api/punchout/transfer builds the OCI fields or the cXML
message and sends it back to the procurement system
The package holds the protocol logic: it reads the setup request, checks the shared secret and builds the transfer in the format the procurement system expects. It runs on the server and has no framework or SDK dependency. Your app owns the routes, the session and the calls to Propeller. Which fields the transfer carries is configurable, see the package README.
In the Accelerator boilerplates
All three boilerplates include PunchOut when you scaffold with --punchout=yes: the three routes above and a Transfer cart to procurement button on the cart page. Without the flag the CLI leaves them out. Turn it on with these settings:
| Setting | What it does |
|---|---|
PUNCHOUT_ENABLED | true turns the PunchOut routes on |
CXML_CONTACT_ID | The ids of the Contacts that cXML buyers sign in as, comma-separated |
PUNCHOUT_DEBUG | true shows the transfer as a readable preview instead of sending it, so you can test without a procurement system |
Each boilerplate's README has a local test recipe.
What to set up in Propeller
- A Contact per buying organization. The procurement system signs the buyer in as this Contact, so its Company determines prices and assortment, as for any Contact.
- The shared secret (cXML). Each cXML buyer's Contact gets the attribute
CXML_SHARED_SECRET, holding the shared secret agreed with the buyer. The setup route compares it with the secret in the setup request. Add the attribute to the Contact attributes the storefront reads (contactTrackAttributesin the boilerplate's config). - A sign-in token (OCI). The OCI entry URL carries a sign-in token (
mtoken) for the buyer's Contact, created withmagicTokenCreate. - The order-editor API key. The boilerplates read the shared secret and create the cXML sign-in tokens with this key, so it needs those rights too. See Keys and security.
See also
- B2B capabilities for the Company and Contact model behind the buyer
- Accelerator for scaffolding with
--punchout=yes - Keys and security for the order-editor key
- Package README for the API and the field mappings