Paybond Kit is a trust and control layer (authorize → prove → release → receipt). It is not a buy-anything HTTP proxy and does not replace merchant storefronts or cart APIs.
Use the multi-provider commerce surface when one agent tool (commerce.checkout) may settle through more than one merchant adapter. Prefer the Shopify-only helper when you only ever check out on Shopify.
When to use which helper
| Helper | Use when |
|---|---|
instrumentShopifyCheckout / @paybond/kit/shopify / paybond_kit.shopify | Single-provider Shopify UCP checkout with binding injection |
instrumentCommerceCheckout / @paybond/kit/commerce / paybond_kit.commerce | One tool routes across Shopify, Stripe, and/or Zinc adapters |
Both inject tenant_id and paybond_intent_id from the Paybond session binding — never from unauthenticated tool args.
What not to do
- Do not build a Gateway “buy-proxy” that accepts arbitrary retailer URLs and purchases on behalf of tenants.
- Do not pass
tenantId/tenant_idorintentId/intent_idin tool arguments — those come from authenticated Paybond bind/attach. - Do not accept free-form checkout amounts from the LLM when a catalog price is available — resolve amounts server-side.
Scaffold
# TypeScript paybond init --template commerce-checkout-agent # Python (same product surface; Python Kit defaults to this twin) paybond init --template commerce-checkout-agent --language python
Creates an agent with Shopify and Stripe mock executors, Zinc sandbox, paybond.policy.yaml (commerce.checkout + cost_and_completion), and a smoke path (npm run smoke for TypeScript, or uv sync / pip install -e . plus paybond agent sandbox smoke … for the Python twin — pure Python, no Node).
TypeScript
import { Paybond } from "@paybond/kit"; import { createShopifyCommerceProvider, createStripeCommerceProvider, createZincCommerceProvider, instrumentCommerceCheckout, } from "@paybond/kit/commerce"; const shopify = createShopifyCommerceProvider({ executeCheckout: async (input) => { // Call UCP / storefront with input.checkoutPayload (binding already stamped). return { status: "completed", cost_cents: input.amountCents, order_id: "gid://shopify/Order/123", shop: input.shopDomain, }; }, }); const stripe = createStripeCommerceProvider({ executeCheckout: async (input) => { // Create/confirm PaymentIntent with input.metadata (tenant + intent bound). return { status: "completed", cost_cents: input.amountCents, payment_intent_id: "pi_test", }; }, }); // Offline mock for e2e — live Zinc HTTP is optional via httpClient. const zinc = createZincCommerceProvider({ mode: "sandbox" }); const paybond = await Paybond.open({ apiKey: process.env.PAYBOND_API_KEY! }); const instrumented = await instrumentCommerceCheckout(paybond, { policy: "shopping", providers: { shopify, stripe, zinc }, defaultProvider: "shopify", }); instrumented.bindingRef.tenantId = tenantId; instrumented.bindingRef.intentId = intentId; await instrumented.bind({ intentId, capabilityToken });
Or wire the router yourself:
import { createCommerceCheckoutRouter } from "@paybond/kit/commerce"; const checkout = createCommerceCheckoutRouter({ providers: { shopify, stripe, zinc }, defaultProvider: "shopify", binding: () => bindingRef, }); await paybond.instrument({ policy: "shopping", tools: { "commerce.checkout": checkout }, });
Tool args select the adapter with provider (defaults to defaultProvider). Provider-specific fields live under shopify, stripe, or zinc.
Python
import os from paybond_kit import Paybond from paybond_kit.commerce import ( create_shopify_commerce_provider, create_stripe_commerce_provider, create_zinc_commerce_provider, instrument_commerce_checkout, ) async def run() -> None: async def execute_shopify(input_payload): # Call UCP / storefront with input_payload["checkout_payload"] (binding stamped). return { "status": "completed", "cost_cents": input_payload["amount_cents"], "order_id": "gid://shopify/Order/123", "shop": input_payload["shop_domain"], } async def execute_stripe(input_payload): # Create/confirm PaymentIntent with input_payload["metadata"]. return { "status": "completed", "cost_cents": input_payload["amount_cents"], "payment_intent_id": "pi_test", } shopify = create_shopify_commerce_provider(execute_checkout=execute_shopify) stripe = create_stripe_commerce_provider(execute_checkout=execute_stripe) zinc = create_zinc_commerce_provider(mode="sandbox") paybond = await Paybond.open(api_key=os.environ["PAYBOND_API_KEY"]) instrumented, binding_ref = await instrument_commerce_checkout( paybond, policy="shopping", providers={"shopify": shopify, "stripe": stripe, "zinc": zinc}, default_provider="shopify", ) binding_ref["tenant_id"] = tenant_id binding_ref["intent_id"] = intent_id await instrumented.bind(intent_id=intent_id, capability_token=capability_token)
Router-only wiring:
from paybond_kit.commerce import create_commerce_checkout_router checkout = create_commerce_checkout_router( providers={"shopify": shopify, "stripe": stripe, "zinc": zinc}, default_provider="shopify", binding=lambda: binding_ref, ) await paybond.instrument( policy="shopping", tools={"commerce.checkout": checkout}, )
Policy snippet
version: 1 name: commerce-checkout-agent-v1 default_deny: true tools: commerce.checkout: side_effecting: true max_spend_cents: 10000 evidence_preset: cost_and_completion intent: allowed_tools: - commerce.checkout budget: currency: usd max_spend_usd: 100
Scaffold with paybond policy init --preset shopping --out paybond.policy.yaml.
Per-provider notes
| Provider | Binding injection | Setup |
|---|---|---|
| Shopify | note_attributes via createCheckoutWithBinding / create_checkout_with_binding | Pass executeCheckout that calls UCP/storefront with the stamped payload |
| Stripe | PaymentIntent metadata (tenant_id, paybond_intent_id, optional rail) | Pass executeCheckout that creates/confirms with input.metadata |
| Zinc | Session ids on the adapter request only | Default mode: "sandbox" (offline). Live: mode: "live" + pluggable httpClient / http_client |
Zinc
- Sandbox (default): deterministic mock orders, no network — use for instrument and smoke tests. Sandbox
cost_centsis product-derived (Σ price_cents × quantity); agentamount_cents/amountCentsmust match and is never trusted alone. Optionalmax_price_centscaps the derived cost. - Live: pass
mode: "live"(exact) and a pluggable HTTP client. Kit does not embed Zinc credentials or a Gateway buy-proxy.
Related
- Shopify CLI workflow — Shopify-only doctor, smoke, and UCP loop
- Guide: multi-provider commerce checkout
- Protect Shopify payments from agents
- Paybond with Stripe agentic commerce