Skip to main content

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)
StartThe procurement system opens your entry URL with a sign-in tokenThe procurement system posts a PunchOutSetupRequest, and your storefront answers with a start URL
Sign-inThe token in the entry URLA one-time token, valid for an hour, created during the setup
Cart backA form of NEW_ITEM-* fields posted to the system's HOOK_URLA 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:

SettingWhat it does
PUNCHOUT_ENABLEDtrue turns the PunchOut routes on
CXML_CONTACT_IDThe ids of the Contacts that cXML buyers sign in as, comma-separated
PUNCHOUT_DEBUGtrue 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 (contactTrackAttributes in 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 with magicTokenCreate.
  • 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​