CDN bundle
The CDN bundle is the zero-framework integration path. Add a single <script> tag to your storefront page; the loader scans for
offer elements, mounts an inline Pay With Agent button, and on click opens
the hosted wallet approve page so the shopper's agent can complete the
purchase.
Install
There is no npm or build step for the browser bundle. Add one <script> tag pointing at the loader on cdn.oid4pay.com:
<script
src="https://cdn.oid4pay.com/oid4ac-merchant/v1/loader.js"
data-merchant-id="merchant_abc123"
></script>The bundle source also ships on npm as @oid4pay/cdn-oid4ac-merchant (v0.1.0, MIT) for teams that want
to self-host the bundle.
Element contract
Mark each purchasable item with a data-oid4ac-offer element. If
the element already contains a <button> the loader wires
it; otherwise it appends its own Pay With Agent button.
<div data-oid4ac-offer
data-sku="demo-tote"
data-amount-minor="1250"
data-currency="EUR"
>
<button>Pay with Agent</button>
</div>The bundle scans for [data-oid4ac-offer] elements on boot
(DOMContentLoaded) and watches for elements added later through
a MutationObserver, so client-rendered and single-page-app
markup is picked up automatically. You can also re-scan a subtree
explicitly with OID4Pay.mountOID4ACButtons(root).
Per-offer attributes
| data-* attribute | Purpose |
|---|---|
data-merchant-id | Merchant id for this offer. Falls back to the loader's data-merchant-id if omitted. Required. |
data-sku | Product SKU. Required. |
data-amount-minor | Price in minor units (integer; must be a finite integer). Required. |
data-currency | ISO 4217 currency code. Required. |
data-availability | Optional. Defaults to InStock. |
data-offer-digest | Optional. A precomputed canonical offer digest; if absent the loader computes it from the other attributes. |
Loader attributes
The loader <script> tag reads only these dataset
attributes:
| data-* attribute | Purpose |
|---|---|
data-merchant-id | Default merchant id applied to offers that do not set their own. |
data-wallet-origin | Optional. Overrides the hosted wallet origin (default https://wallet.oid4pay.com). |
data-as-origin | Optional. Overrides the Authorization Server origin (default https://as.oid4pay.com). |
Checkout flow
On click, the bundle computes the canonical offer digest (unless data-offer-digest was supplied) and opens the hosted wallet
approve page at the wallet origin:
https://wallet.oid4pay.com/approve
?offer=<offer_digest>
&merchant_id=<merchant_id>
&sku=<sku>
&amount_minor=<amount_minor>
¤cy=<currency>The approve page is opened as a sandboxed modal overlay, falling back to a popup and then a same-tab navigation when a strict Content Security Policy blocks the overlay. The agent and shopper complete approval and consent on the hosted wallet; settlement is carried out downstream by the merchant over its chosen payment rail. The browser bundle never charges and never holds a token.
Browser surface
The bundle exposes a global namespace window.OID4Pay with these
nine members:
| Member | Purpose |
|---|---|
configure(options) | Override merchantId, walletOrigin, or asOrigin at runtime. |
mountOID4ACButtons(root) | Re-scan root for new [data-oid4ac-offer] elements. |
openApproveModal(offer) | Open the wallet approve flow for an offer object without a click event. |
canonicalOfferDigest(body) | Compute the canonical SHA-256 digest of an Offer body. |
verifyOffer(body, headers, jwks) | Verify an RFC 9421 signed offer in the browser using WebCrypto Ed25519. |
verifyCatalog(body, jwksOrUrl) | Verify a signed merchant catalog body served from /.well-known/oid4ac-catalog. |
pickInStock(items) | Return only the in-stock items from a verified catalog. |
pickCheapestMatching(items, skuPattern) | Return the cheapest in-stock item matching a SKU pattern, or null. |
version | The bundle version string. |
Events
The bundle dispatches a single browser event, oid4pay:metric, on every verifier and JWKS milestone. Wire one
listener:
window.addEventListener("oid4pay:metric", (ev) => {
// ev.detail = { kind, name?, code?, attempt?, delayMs?, urlHint? }
analytics.send("oid4pay." + ev.detail.kind, ev.detail);
});The emitters never log the Authorization header, raw signature
bytes, or any compact mandate string.
Browser support
Chromium 113+ and Firefox 130+. The bundle uses the WebCrypto Ed25519 algorithm directly; browsers without WebCrypto Ed25519
cannot run the in-browser verifier.
Content Security Policy
Content-Security-Policy:
default-src 'self';
script-src 'self' https://cdn.oid4pay.com;
frame-src https://wallet.oid4pay.com;Algorithm whitelist
The CDN bundle verifies signed offers and signed catalogs using WebCrypto Ed25519 only. hmac-sha256, rsa-pss-sha512, and ecdsa-p256-sha256 are refused; ecdsa-p256-sha256 is not bundled, so a merchant using P-256
verifies away from the browser.
What the CDN does not verify
The browser is a hostile environment for trust-rooted code, so the bundle's verifier scope is deliberately narrow. It verifies RFC 9421 signed offers and signed catalogs in the browser. It does not verify SD-JWT VC mandates and does not verify JWT access tokens in the browser; both are kept out of the browser on purpose. Mandate and token verification belong on your server (via the Node, Python, or Go SDK) or on the hosted wallet.
Source
The bundle lives at sdks/cdn-oid4ac-merchant/ in the OID4Pay
repo and publishes to cdn.oid4pay.com under the v1 URL path. A breaking wire-version bump ships under a new v2 path while the old bundle stays at v1. The
bundle source is also published on npm as @oid4pay/cdn-oid4ac-merchant.