Skip to content

Magento 2

The punchout.dev module PunchoutDev_Bridge for Magento 2.4 prints the script tag, marks the cart page for punchout.dev and signs punchout buyers in to their customer account.

Requirement Value
Magento 2.4, Open Source or Commerce
PHP 8.1 to 8.4, with sodium and json
Module PunchoutDev_Bridge (composer name punchout-dev/module-bridge), version 2.0.0, no Composer dependencies
Download PunchoutDev-Bridge-<version>.zip from the shop’s Embed tab in the portal (Shop platform: Magento)

The zip already contains the folders PunchoutDev/Bridge/. Unpack it into app/code, so the module lands in app/code/PunchoutDev/Bridge. Then run:

Terminal window
bin/magento module:enable PunchoutDev_Bridge
bin/magento setup:upgrade
bin/magento cache:flush

In production mode, also run:

Terminal window
bin/magento setup:di:compile
bin/magento setup:static-content:deploy

setup:upgrade creates one table for single-use login tokens. Nothing else in the database is touched.

Open Stores → Configuration → punchout.dev → General. You can set each value at default, website or store-view scope. The configuration paths start with punchout_dev/general/.

Setting Path Value
Embed the snippet snippet_enabled Yes (default). No prints no script tag.
Snippet URL snippet_url https://js.punchout.dev/pob.js, from the portal’s Embed tab. Empty prints nothing.
API base URL (optional) api_base Leave empty.
Enable auto-login enabled Yes (default).
Shop ID tenant_id The Shop ID from the portal’s Embed tab. Also printed as data-shop-id on the script tag.
Public key lines public_keys Every line from the portal’s Auto-login tab, section Public keys, one per line. Lines starting with # and blank lines are ignored.

The same values from the command line:

Terminal window
bin/magento config:set punchout_dev/general/tenant_id pob_live_…
bin/magento config:set punchout_dev/general/public_keys "k1=…"
bin/magento config:set punchout_dev/general/snippet_url https://js.punchout.dev/pob.js
bin/magento cache:flush

The module prints the script tag into before.body.end on every storefront page.

The module puts an afterToHtml interceptor on Magento\Checkout\Block\Cart\Grid and wraps its output in <div data-punchout-cart>. It acts only on the block named checkout.cart.form, the cart form on the cart page, so a mini cart or another listing built from the same class is never marked. The marker follows the block class, not the template, and works in Luma and Hyvä alike. An empty cart is left unmarked.

The module’s login endpoint is GET /punchout-dev/login?token=…. It is a frontend route and never resolves in the admin area. Set up the portal side on the shop’s Auto-login tab:

Portal field Value
Adapter Magento
Login path /punchout-dev/login, prefixed with the store’s base path when the shop does not sit at the domain root, for example /shop/pub/punchout-dev/login
Customer reference Email address (recommended) or Customer ID
Customer reference Matched against
Email address A customer of the current website with that address
Customer ID The Magento customer entity ID, on the current website
Customer number Not supported

Then give each buyer credential its Shop customer reference on the Buyers tab. A customer still waiting for their email confirmation is not signed in. Admin users cannot be signed in this way at all: they live in a separate table that the customer login never reads.

After the login, the module redirects to the landing path as it is, without adding the store’s base path. Set the Landing path on the General tab to the full cart path, for example /checkout/cart/, or /shop/pub/checkout/cart/ for a store under a sub-path.

The full flow is on the Auto-login page.

Magento 2.4 ships the Magento_Csp module. In report-only mode, the script tag loads without changes. If the storefront enforces its policy, the policy must allow the script tag’s sources. The punchout.dev module ships no csp_whitelist.xml, because the snippet URL is a setting. The portal’s Embed tab shows the four lines for your shop:

script-src https://js.punchout.dev
connect-src https://api.punchout.dev
style-src 'unsafe-inline'
form-action https://<host of each buyer system>:*

style-src 'unsafe-inline' is needed because the panel’s styles are inline. form-action is needed because the cart is handed to the buyer system from the shop page. The Embed tab builds that line from Allowed return hosts on the General tab, one https://<host>:* per host, and shows the placeholder https://buyer-system.example while the list is empty. For the test punchout, form-action must also allow https://api.punchout.dev. The full explanation is on Install the tag.

  1. On the shop’s Setup tab in the portal, create a setup link (valid 60 minutes by default).
  2. Put 2 or 3 different products in the cart.
  3. Open the cart page with the setup link and click Detect cart.

With the module in place, the result names the source Shop plugin. Confirm with Yes, that’s it. That completes the Cart detected step in the portal.

Download the new zip from the Embed tab, unpack it over app/code/PunchoutDev/Bridge, then run bin/magento setup:upgrade and bin/magento cache:flush (plus the two production-mode commands). Magento can keep serving the previous template after files are replaced in place. Clear its preprocessed copy as well:

Terminal window
rm -rf var/view_preprocessed/pub/static/app/code/PunchoutDev

To Magento, 2.0.0 is a new module: run bin/magento module:disable PunchoutNinja_Bridge, delete app/code/PunchoutNinja and never run both. Enter the values again under Stores → Configuration → punchout.dev and change the portal’s Login path to /punchout-dev/login.

The module writes one info line per login to var/log/system.log, with a reason word when it refuses the token. It never logs the token or the customer. Magento-specific reasons:

Reason Meaning
unsupported_ref_kind The portal’s Customer reference is Customer number
customer_unresolved No customer matches on this website
customer_wrong_website The customer ID belongs to another website
customer_unconfirmed The customer has not confirmed their email address
store_unresolved The current store could not be determined

The common reason words are on the Auto-login page. For more, see Troubleshooting.

The module’s README covers the token checks and the development tests: Magento module README.