paybondpaybond
Sign in

T23 · Tutorial

Production Stripe & Shopify charges

Guard live Stripe charges and Shopify checkouts after production attach: policy presets, server-side amounts, binding metadata, partner secrets.

~40 minAdvancedProductionproductcommerceLifecycle pipeline

Outcome: payments.charge_customer (stripe_charge) and/or commerce.checkout run on live attach with server-owned amounts and partner keys in secrets only.

Learning view: objectives and extras expanded. Switch for commands only.

Mental model

Providers move money; Kit authorizes the tool and signs completion evidence. Sandbox smokes are contract-only; live needs attach + partner secrets.

You will be able to

  • Scaffold stripe-commerce or shopping policy and validate-tools before deploy
  • Instrument at charge/checkout boundary; keep provider SDKs inside handlers
  • Load amounts from invoice/catalog — never free-form model amount_cents
  • Attach binding metadata (buildPaybondStripeMetadata / Shopify note attributes)
  • Bind with intentId + capabilityToken (or attach: env) — never sandbox: true for live charges
  • Name which smoke is sandbox contract vs funded production attach

Prerequisites

  • · Protect first agent tool (production) — live open, deferred instrument, funded bind
  • · Settlement rail for your provider path (Stripe Connect / Shopify)
  • · For real money: STRIPE_SECRET_KEY and/or Shopify credentials in secrets manager — not required for policy and sandbox contract smoke

Provider charges on production attach

Stripe and Shopify execute the payment; Kit authorizes the tool and signs completion evidence. Sandbox presets prove the contract without partner credentials — live money needs production attach (previous tutorials) plus provider secrets.

  1. 01

    Settlement and live open

    Rails in Settlement; Paybond.open expectedEnvironment live.

  2. 02

    Provider policy

    stripe-commerce or shopping policy; validate-tools --local-only.

  3. 03

    Funded attach

    intentId and capabilityToken or attach: env (not sandbox smoke).

  4. 04

    Guard charge tool

    Instrument charge/checkout; amount from invoice/catalog.

  5. 05

    Evidence and Console

    stripe_charge / completion evidence; inspect Intents / Agent runs.

Policy and sandbox contract (no partner money)

Contract only — not live attach
  1. Step 1 of 4

    Scaffold Stripe commerce policy

    Adjust ceilings before deploy. Shopping preset for Shopify path.

    Goal: Same policy schema as sandbox; register payments.charge_customer (stripe_charge) or commerce.checkout.

    Run this

    paybond policy init --preset stripe-commerce --out paybond.policy.yaml
    # Shopify/shopping alternative:
    # paybond policy init --preset shopping --out paybond.policy.yaml

    Example response

    Wrote paybond.policy.yaml (stripe-commerce preset)
    tools:
      payments.charge_customer
        evidence_preset: stripe_charge

    You should see: paybond.policy.yaml lists your charge/checkout tool with evidence_preset.

  2. Step 2 of 4

    Validate policy locally

    CI-friendly check without Gateway credentials.

    Goal: Catch allowlist / evidence misconfig before a live deny.

    Run this

    paybond policy validate-tools --file paybond.policy.yaml --local-only

    Example response

    ✓ tools registry ok
    ✓ every side-effecting tool has evidence_preset
    ✓ intent.allowed_tools aligned

    You should see: Exit 0.

  3. Step 3 of 4

    Sandbox stripe contract (optional)

    No Stripe secret required — synthetic stripe_charge evidence path only.

    Goal: Rehearse the evidence contract without partner charge APIs.

    Run this

    paybond agent sandbox smoke --preset stripe-commerce --format table

    Example response

    PHASE       DETAIL
    authorize   payments.charge_customer   ok
    charge      synthetic stripe_charge
    evidence    verified · released

    You should see: Spend approved · Charge completed · Evidence verified (table).

    Note: Still not live attach. For attach smoke use the previous tutorial after fund.

  4. Step 4 of 4

    Sandbox Shopify checkout contract (optional)

    No Shopify store required for this sandboxed guardrail path.

    Goal: Same guardrail shape you will wire with instrumentShopifyCheckout on live.

    Run this

    paybond agent sandbox smoke \
      --operation commerce.checkout \
      --requested-spend-cents 4500 \
      --evidence-preset cost_and_completion \
      --format table

    Example response

    PHASE       OP                  RESULT
    authorize   commerce.checkout   ok
    evidence    cost_and_completion released
    # contract only — not live UCP money

    You should see: Spend approved · checkout path and receipt stages in table.

Live preconditions (honest)

Real charges and checkouts need more than sandbox smoke. Complete production attach first, then inject partner credentials only into the agent runtime secrets manager.

  • Paybond: paybond_sk_live_…, expectedEnvironment live, funded intent and capability_token (or PAYBOND_ATTACH_* and PAYBOND_ATTACH_BUNDLE).
  • Stripe live path: STRIPE_SECRET_KEY (and Settlement Stripe Connect already configured). Optional: mapStripeToolResultToEvidence after charge.
  • Shopify live path: store domain and Admin / storefront / UCP credentials you already use for checkout — Kit does not ship fake Shopify APIs.
  • Amounts: invoice.amount_due or catalog unit price × quantity — never free-form model amount_cents.
  • Console: Settlement for rails; Machine access for keys/bundles; Intents and Agent runs after execute.

Step-by-step product wiring

Guard payments.charge_customer with stripe_charge evidence. Load amount from a trusted invoice; attach buildPaybondStripeMetadata so webhooks can bind tenant and intent. Full recipe: Charge customers from agents.

  • Open with expectedEnvironment live — omit sandbox bootstrap.
  • Pass invoiceId (not amountCents) from trusted session context.
  • mapStripeToolResultToEvidence rejects funding webhook envelopes as completion evidence.
  • Bind after create/fund; inspect evidence under Console Intents / Agent runs.

Load amount from Stripe (invoice/server), attach Paybond metadata, return evidence-shaped tool result.

stripe-charge.ts

TS
TypeScript: Stripe charge toolSwipe to inspect long lines
import Stripe from "stripe";
import {
  Paybond,
  buildPaybondStripeMetadata,
  mapStripeToolResultToEvidence,
} from "@paybond/kit";

const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!); // partner secret
const paybond = await Paybond.open({
  apiKey: process.env.PAYBOND_API_KEY!,
  expectedEnvironment: "live",
});

async function chargeCustomer(args: {
  customerId: string;
  invoiceId: string; // trusted — load amount server-side
  tenantId: string;
  intentId: string;
}) {
  const invoice = await stripe.invoices.retrieve(args.invoiceId);
  const amountCents = invoice.amount_due;
  const metadata = buildPaybondStripeMetadata({
    tenantId: args.tenantId,
    intentId: args.intentId,
    rail: "stripe_connect",
  });
  const pi = await stripe.paymentIntents.create({
    amount: amountCents,
    currency: invoice.currency,
    customer: args.customerId,
    confirm: true,
    metadata,
    automatic_payment_methods: { enabled: true },
  });
  const toolResult = {
    status: pi.status,
    cost_cents: amountCents,
    invoice_id: invoice.id,
    payment_intent_id: pi.id,
    charge_id:
      typeof pi.latest_charge === "string"
        ? pi.latest_charge
        : pi.latest_charge?.id,
  };
  mapStripeToolResultToEvidence(toolResult, { preset: "stripe_charge" });
  return toolResult;
}

const instrumented = await paybond.instrument({
  policy: "./paybond.policy.yaml",
  tools: { "payments.charge_customer": chargeCustomer },
});
// Production: await instrumented.bind({ intentId, capabilityToken });
// Omit sandbox bootstrap for live charges.

Result: Partner Stripe charge succeeds only after Kit spend authorize; evidence maps via stripe_charge.

Also: Production attach · Paybond with Stripe agentic commerce · Paybond with Shopify agentic commerce.

Verify before you continue

Check these off against your terminal or timeline output — progress stays on this device.

0/6

If something goes wrong

  • If you see

    Accepting amountCents from the LLM for Stripe charge

    Do this

    Pass trusted invoiceId (or order id); load amount_due server-side in the handler before PaymentIntent create.

  • If you see

    Using payment_intent.succeeded webhook body as tool evidence

    Do this

    mapStripeToolResultToEvidence rejects funding webhook shapes — submit tool-result evidence after the guarded charge returns.

  • If you see

    Shopify order webhooks treated as completion evidence

    Do this

    orders/create and orders/paid are funding/binding signals; completion evidence still follows the guarded checkout tool under capability_token.

  • If you see

    Deploy still has sandbox: true on commerce instrument

    Do this

    Production: deferred instrument and bind({ intentId, capabilityToken }) or attach: "env" after fund — same as Protect first agent tool (production).

Self-check

Answer without scrolling up — then reveal the model answer to compare.

Why can paybond agent sandbox smoke --preset stripe-commerce be green while live charges still fail, and what two secret classes are missing?

Next steps

Pick a branch — not every path needs every tutorial.

Recipes are copy-paste production smokes — not repeated inside this tutorial.