paybondpaybond
Sign in

Fund intents by rail

Production guide to creating Paybond intents and funding them on Stripe Connect, ACH debit, or x402 USDC — then using capability tokens with spend guard middleware.

This guide covers Steps 1–3 of How intent funding works: create a signed intent, fund it on the chosen rail, and use the returned capability_token with spend guard middleware.

Settlement rails must already be configured — see Configure settlement rails for tenant-admin console setup.

Open a tenant-bound session

Kit derives tenant scope from the service-account API key. Never pass tenant ids from unauthenticated user input.

import { Paybond } from "@paybond/kit";

const paybond = await Paybond.open({
  apiKey: process.env.PAYBOND_API_KEY!,
  expectedEnvironment: "production",
});

Python: paybond = await Paybond.open(api_key=..., expected_environment="production").

Use sandbox credentials and expectedEnvironment: "sandbox" for rehearsal. For the fastest sandbox path without intent create, use one-command guardrails.

Step 1 — Create a signed intent

The principal signs budget, payee, deadline, allowed operations, evidence requirements, and settlement_rail. Pick a completion preset aligned with the rail when you want catalog-bound evidence.

const created = await paybond.intents.create({
  operation: "travel.book_hotel",
  requestedSpendCents: 20_000,
  currency: "usd",
  settlementRail: "stripe_connect",
  completionPreset: "api_response_ok",
  // principal signing, payee, predicate, deadline — see quickstart
});
created = await paybond.intents.create(
    operation="travel.book_hotel",
    requested_spend_cents=20_000,
    currency="usd",
    settlement_rail="stripe_connect",
    completion_preset="api_response_ok",
)

settlement_rail requests one allowed rail. Harbor resolves the payee destination from tenant settlement config — your create payload does not include Stripe account ids or wallet addresses.

Step 2 — Fund on the rail

RailTypical funding pathcapability_token timing
stripe_connectPaymentIntent authorized during create (or immediately after)Often in the create response
stripe_ach_debitBank debit initiated; Harbor waits for Stripe confirmationAfter payment_intent.succeeded — may require waiting or polling
x402_usdc_basepaybond.intents.fund x402 handshake on POST /harbor/intents/{id}/fundAfter authorization succeeds on Base

Stripe Connect (immediate)

When create returns capability_token (or capabilityToken), funding is complete:

const intentId = created.intent_id;
const capabilityToken = created.capability_token;
if (!capabilityToken) {
  throw new Error("expected funded intent on stripe_connect");
}

ACH debit (delayed)

Create may return an intent without a capability token. Wait until Harbor reports funded, then read the token from intent state or fund retry helpers your integration layer provides. Do not run paid tools while the bank debit is pending.

x402 USDC (payment-session handshake)

Kit wraps Harbor's 402 → sign → retry flow:

const fundProof = await issueAgentRecognitionProofV1({
  purpose: "harbor.intent.fund",
  method: "POST",
  path: `/harbor/intents/${intentId}/fund`,
  body: {},
});

let funded = await paybond.intents.fund({ intentId, recognitionProof: fundProof });

if (funded.statusCode === 402 && funded.paymentRequired) {
  const paymentSignature = await x402Wallet.signPayment(funded.paymentRequired);
  const retryProof = await issueAgentRecognitionProofV1({ /* same path */ });
  funded = await paybond.intents.fund({
    intentId,
    recognitionProof: retryProof,
    paymentSignature,
  });
}

const capabilityToken = funded.capabilityToken;

See TypeScript quickstart — Stablecoin funding and Python quickstart for full signing helpers.

MCP hosts

Use paybond_create_spend_intent and paybond_fund_intent over stdio MCP, then pass the returned intent_id and capability_token to paybond_authorize_agent_spend before side-effecting tools.

Step 3 — Authorize spend before tool work

Capabilities are intent-scoped credentials — not API keys. Harbor mints them at funded; there is no separate issuance endpoint.

const guard = paybond.spendGuard(intentId, capabilityToken);
await guard.authorizeSpend({
  operation: "travel.book_hotel",
  requestedSpendCents: 20_000,
});
guard = paybond.spend_guard(intent_id, capability_token)
await guard.authorize_spend(
    operation="travel.book_hotel",
    requested_spend_cents=20_000,
)

For multi-tool agents, prefer agent middleware (PaybondAgentRun + PaybondToolRegistry) so every side-effecting tool shares one intent and auto-evidence.

Wrap handlers with guardTool / guard_tool or call authorizeSpend immediately before vendor API calls.

After funding — evidence and settlement

Funding authorizes spend up to the intent budget. It does not release money to the payee.

  1. Run the guarded tool and collect completion fields (API status, vendor refs, signed receipts — not funding webhook payloads).
  2. Submit evidence via paybond.intents.submitEvidence / submit_evidence.
  3. Harbor evaluates the predicate and confirms release or refund.

See Completion presets — Funding vs completion and How agent settlement works.

Rail-specific integration checklists

stripe_connect

  1. Confirm settlement console shows linked Connect destination and allowed rail.
  2. Create intent with settlementRail: "stripe_connect".
  3. Read capability_token from create when funded.
  4. Guard tool → submit api_response_ok or matching preset evidence.

stripe_ach_debit

  1. Confirm ACH capability is ready in settlement console.
  2. Create intent with settlement_rail: "stripe_ach_debit".
  3. Wait for funded after bank debit confirms.
  4. Guard tool → submit ach_paid_api_ok or matching ACH preset evidence.

x402_usdc_base

  1. Confirm Base receive address is saved in tenant config.
  2. Create intent with settlementRail: "x402_usdc_base" (budget still USD cents).
  3. Complete /fund handshake until authorization_succeeded.
  4. Guard tool → submit x402_paid_api_ok, x402_delivery_receipt, or x402_cost_and_completion.

Common questions

Why did create not return a capability token?

The rail may be delayed (stripe_ach_debit, x402_usdc_base) or funding failed. Inspect intent state in the operator console or Harbor API before retrying tool calls.

Can I reuse a capability across intents?

No. Capability tokens are bound to one intent_id and minted when that intent reaches funded.

Is funding the same as releasing to the payee?

No. Funding escrow-authorizes spend. Release happens after evidence passes the intent predicate and settlement is confirmed.

Where to go next