Paybond ships a completion preset catalog as the single source of truth for strong, generic completion archetypes. Harbor managed templates, the policy registry console, Kit CLI scaffolding, and docs all consume the same preset IDs and field names.
Canonical file: completion preset catalog (catalog.json)
JSON Schema: completion preset catalog schema (catalog.schema.json)
Why presets exist
Spend guardrails (gateway authorize) and completion predicates (Harbor release) are separate layers. Presets tie them together with:
- A stable preset ID for docs and CLI (
api_response_ok, not vendor-specific names in v1) - A Harbor template ID that materializes parameters into validated
predicate_dsl - Evidence schema and sample pass/fail payloads for preview and test
- Optional spend hints for documentation (not auto-enforced in v1)
Predicate evaluation stays in Harbor. Your integration collects HTTP responses, webhooks, or artifact hashes and places structured fields in signed evidence — the VM never calls external APIs.
Agent middleware policy files reference preset IDs via evidence_preset in paybond.policy.yaml. Validate preset alignment with paybond policy validate-tools --file paybond.policy.yaml.
Funding vs completion
Paybond enforces a two-layer model. Funding webhooks and authorization payloads move an intent to funded and issue a capability_token. Completion evidence proves the paid tool ran and predicates evaluate that payload only — rail-agnostic, separate from settlement state.
flowchart LR
subgraph funding [Funding layer - Harbor internal]
create[Intent create]
fund[Fund / webhooks / x402 auth]
funded[state=funded + capability_token]
end
subgraph completion [Completion layer - payee evidence]
tool[Execute paid tool]
evidence[Submit evidence JSON]
predicate[Predicate eval]
settle[Capture / transfer / void]
end
create --> fund --> funded --> tool --> evidence --> predicate --> settle| Rail | Funding signal (NOT evidence) | Tool completion evidence (catalog) |
|---|---|---|
stripe_connect | Card PaymentIntent succeeded / capture | api_response_ok, vendor_webhook_confirmed, artifact_attested |
stripe_ach_debit | payment_intent.succeeded → funded (Harbor internal) | Same archetypes; never submit PI/charge/mandate ids as payee evidence |
x402_usdc_base | authorization_succeeded via /fund + Coinbase webhooks | Same archetypes; never submit payment_session_id / authorization_id / auth tx hashes as payee evidence |
Harbor stores rail fields in settlement provider state; predicates evaluate rail-agnostic evidence.payload only. Completion presets do not replace funding webhooks — use the ACH integration checklist and x402 integration checklist below for settlement triage.
ACH integration checklist (stripe_ach_debit)
- Fund gate — Wait for Harbor
fundedafter Stripe confirms bank debit (payment_intent.succeededis funding only). - Capability — Read
capability_tokenfrom the funded intent; pass it to your spend guard before tool calls. - Tool proof — Call the vendor API or receive an async vendor webhook after the tool completes.
- Evidence — Submit tool-completion fields via
ach_paid_api_ok,ach_travel_booking, orach_vendor_webhook(not Stripe funding payloads). - Transfer / refund — On predicate pass, Harbor settles via Connect transfer; on failure, use the canonical refund path.
sequenceDiagram
participant Agent
participant Harbor
participant Stripe
participant VendorTool
Agent->>Harbor: fund until capability_token
Note over Harbor,Stripe: payment_intent.succeeded = FUNDING only
Agent->>VendorTool: paid API call with capability
VendorTool-->>Agent: HTTP 200 + confirmation_number
Agent->>Harbor: evidence via ach_paid_api_ok or ach_travel_booking
Harbor->>Harbor: predicate pass
Harbor->>Stripe: Connect transfer on releasex402 integration checklist (x402_usdc_base)
- Fund until
capability_token— Complete/fund(402→PAYMENT-SIGNATUREretry) until Harbor reportsauthorization_succeeded. - Tool proof — Call the paid tool with the capability; optionally collect an x402 Signed Offer & Receipt on the response.
- Evidence — Submit via
x402_paid_api_ok,x402_delivery_receipt, orx402_cost_and_completion(not Coinbase session ids). - Capture / void — On predicate pass, Harbor captures USDC; on failure, void the authorization.
sequenceDiagram
participant Agent
participant Harbor
participant Coinbase
participant VendorTool
Agent->>Harbor: fund until authorization_succeeded
Note over Harbor,Coinbase: authorization = FUNDING only
Agent->>VendorTool: paid call with capability_token
VendorTool-->>Agent: result + optional x402 signed receipt
Agent->>Harbor: evidence via x402_delivery_receipt or x402_paid_api_ok
Harbor->>Coinbase: capture on predicate passv1 archetypes
| Preset ID | Harbor template | Minimum evidence fields | Predicate intent |
|---|---|---|---|
api_response_ok | api_response_v1 | http_status, vendor_ref_id, response_digest | HTTP status equals expected value; required string fields match schema |
webhook_confirmed | webhook_confirmation_v1 | webhook_event_id, event_type, payload_digest | Event type matches; webhook id and digest present |
artifact_attested | artifact_hash_v1 | artifact_blake3_hex, operation, vendor_ref_id | Non-empty hash array; operation matches; vendor ref present |
cost_and_completion | completion_budget_v1 | status, cost_cents | Status completed; cost within intent amount_cents |
sandbox_permissive | true_v1 | optional smoke fields | Always pass (explicit opt-in for sandbox) |
Using presets in the console
- Open Configuration → Policies in the admin console.
- Select a template such as
api_response_v1. - Use the Recommended archetype picker — rail hints and anti-patterns appear for vendor packs.
- Use the pre-filled Parameters, Evidence, and Evidence schema in the sandbox panel (defaults match this catalog).
- Run Preview to see materialized DSL, then Test evaluate with sample evidence.
Add template IDs to your tenant allowed_policy_templates guardrail list before publishing in enforce mode. New tenants provisioned after the completion archetype rollout receive these template IDs in their default allow-list automatically (observe mode until you switch to enforce).
After you choose a settlement rail (stripe_connect, stripe_ach_debit, or x402_usdc_base), pick a matching vendor pack from the catalog — see the TypeScript quickstart.
Tenant defaults
Signup provisioning seeds allowed_policy_templates with every Harbor template id from this catalog so archetypes can be published without manual allowlist editing. Only tenants with no guardrail policy row receive these defaults when the gateway schema bootstrap runs (paybond-gateway-bootstrap after schema.sql) or at signup. An empty allowed_policy_templates list on an existing policy is intentional and is not overwritten — operators who want archetype templates must add them explicitly or publish a new guardrail policy version.
The sql migration 20260625_completion_archetype_guardrail_defaults is a one-time snapshot for environments that apply migrations manually; it seeds the same template list for tenants with no policy row. When the catalog gains new Harbor templates, update the migration array or rely on bootstrap/signup seeding (guarded by TestDefaultAllowedPolicyTemplateIDs_matchCatalog in Go).
Schema validation vs predicate release
When a completion preset is bound at intent create, Harbor validates canonical and optional vendor evidence against the frozen schemas pinned on the intent row. This is signal-only in v1: validation failures appear in schema_validation and Signal COMPLETION_* fraud signals, but evidence submission still succeeds and the predicate may still pass release. A passing predicate does not guarantee vendor schema conformance — alert on passed_with_drift and pack_stale in production workflows.
Catalog entry shape
Each preset in catalog.json includes:
| Field | Purpose |
|---|---|
preset_id | Stable archetype name for CLI and docs |
harbor_template_id | Managed template passed to Harbor policy APIs |
parameters | Default tenant parameters for materialization |
evidence_schema | JSON Schema-style object for intent evidence_schema |
sample_evidence | Payload that should pass policy test |
sample_failing_evidence | Payload that should fail (except sandbox_permissive) |
human_summary | Operator-facing one-liner |
spend_hints | Optional recommended gateway spend caps (documentation only in v1) |
scope | tool_completion or sandbox_smoke — explicit lifecycle scope |
rail_hints | Settlement rails this pack is documented for (filter/docs only) |
forbidden_evidence_fields | Rail-owned ids that must not appear in payee evidence |
anti_patterns | Human-readable warnings surfaced in docs and console |
Vendor packs add kind: "vendor_pack", archetype_preset_id, evidence_field_map, and optional vendor_evidence_schema / vendor_sample_evidence.
Example: API response OK
Parameters (from catalog):
{ "http_status_path": ["http_status"], "expected_http_status": 200 }
Sample passing evidence:
{ "http_status": 200, "vendor_ref_id": "ch_3NxExample", "response_digest": "blake3:7f83b1657ff1fc53b92dc18148a1d65dfc2d4b1fa3d677284addd200126d9069" }
Materialized predicate (via POST /harbor/policy/v1/preview):
{ "version": 1, "root": { "op": "and", "clauses": [ { "op": "eq", "path": ["http_status"], "value": 200 }, { "op": "schema_field", "field": "vendor_ref_id" }, { "op": "schema_field", "field": "response_digest" } ] } }
Example: Artifact attested
Materialized predicate for artifact_hash_v1:
{ "version": 1, "root": { "op": "and", "clauses": [ { "op": "schema_field", "field": "artifact_blake3_hex" }, { "op": "array_nonempty", "field": "artifact_blake3_hex" }, { "op": "completion", "path": ["operation"], "value": "attested" }, { "op": "schema_field", "field": "vendor_ref_id" } ] } }
An empty artifact_blake3_hex array fails at the array_nonempty clause even when operation and vendor_ref_id are present.
Anti-patterns
- Funding webhooks in evidence — Stripe
payment_intent.succeeded, Coinbaseauthorization_succeeded, and x402 payment-session payloads are funding signals. Harbor consumes them internally; do not submit them as tool-completion evidence. - x402 session ids in evidence —
payment_session_id,authorization_id, and on-chain auth transaction hashes belong in settlement provider state, not payee evidence. - HTTP 200 alone — pair status checks with
vendor_ref_idand a content digest so evidence is bound to a specific response body. - Raw predicate DSL in production — prefer publishing a managed template head and binding with
policy_binding(signing v7). - Mismatched field names — align init scaffolds and evidence builders with catalog canonical names (
cost_cents, not ad-hoc aliases). - Deprecated
stripe_webhook_payment— usevendor_webhook_confirmedfor vendor SaaS job/order webhooks; never Stripe funding event types.
Related
- Harbor predicate DSL — clause reference and managed template table
- Evidence & artifacts
- One-command guardrails
Vendor packs and receipt import
Vendor packs
Named vendor packs are thin wrappers over archetypes. They reuse the same Harbor template and predicate materialization while exposing vendor-friendly evidence field names via evidence_field_map. rail_hints are documentation and console filter hints only — predicates stay rail-agnostic.
| Vendor pack | Archetype | Pinned api_version | Rail hints | Field mapping |
|---|---|---|---|---|
stripe_charge | api_response_ok | 2024-10-28.acacia | stripe_connect | charge_id → vendor_ref_id |
vendor_webhook_confirmed | webhook_confirmed | vendor_webhook_v1 | — | webhook_event_id, neutral job.completed default |
stripe_webhook_payment | webhook_confirmed | stripe_webhook_legacy_v1 | stripe_connect | Deprecated — use vendor_webhook_confirmed |
ach_paid_api_ok | api_response_ok | ach_paid_api_v1 | stripe_ach_debit | confirmation_number → vendor_ref_id |
ach_travel_booking | cost_and_completion | ach_travel_booking_v1 | stripe_ach_debit | confirmation_number, total_cents, fare_class |
ach_vendor_webhook | webhook_confirmed | ach_vendor_webhook_v1 | stripe_ach_debit | vendor_event_id → webhook_event_id, booking.confirmed |
x402_paid_api_ok | api_response_ok | x402_api_v1 | x402_usdc_base | standard HTTP completion fields |
x402_delivery_receipt | artifact_attested | x402_receipt_v1 | x402_usdc_base | receipt_digest → artifact_blake3_hex[0], resource_url → vendor_ref_id |
x402_cost_and_completion | cost_and_completion | x402_metered_v1 | x402_usdc_base | standard status / cost_cents |
Scaffold with paybond init completion --preset ach_paid_api_ok (or any preset id). The generated helper maps vendor fields to canonical names before evidence submit.
Evidence example (ach_travel_booking):
{ "confirmation_number": "AA-8JZ3QK", "total_cents": 19750, "fare_class": "economy", "status": "completed" }
Evidence example (x402_delivery_receipt canonical):
{ "artifact_blake3_hex": ["<digest of signed x402 receipt>"], "operation": "attested", "vendor_ref_id": "https://api.vendor.example/job/123" }
MCP SEP-2828 receipt import
Pair a cryptographically signed decision record (pre-side-effect) with a signed outcome record (post-execution). The CLI verifies signatures before mapping into artifact_attested evidence:
paybond policy import-mcp-receipt \ --decision-file decision.json \ --outcome-file outcome.json \ --write-evidence-file evidence.json
Signature requirements (both records):
- Each record must carry an Ed25519 signature over SHA-256 of JCS-canonical JSON with signature fields stripped.
- Signatures live in
issuerAsserted(decision) orreceiptAsserted(outcome), or at the record root, ased25519_signature_hex+signing_public_key_ed25519_hex. - Pairing checks:
backLink.attestationDigestmust match on both records;outcomeDerived.decisionDigestmust equal the signed decision record digest. - Unsigned or tampered records are rejected — bare field mapping without verification is not supported.
Mapped evidence fields:
artifact_blake3_hexfromoutcomeDerived.decisionDigestandresultCommitmentoperationtoattestedwhenoutcomeDerived.statusisexecutedvendor_ref_idfrombackLink.attestationDigest
Minimal signed decision shape (outcome mirrors with receiptAsserted and outcomeDerived):
{ "backLink": { "attestationDigest": "sha256:deadbeef", "attestationNonce": "nonce-1" }, "decisionDerived": { "decision": "allow" }, "issuerAsserted": { "iss": "did:example:mcp-server", "signing_public_key_ed25519_hex": "<32-byte hex>", "ed25519_signature_hex": "<64-byte hex>" } }
x402 Signed Receipt import
Import a signed x402 offer-receipt artifact (tool delivery proof, not funding). The CLI verifies the signature before mapping:
paybond policy import-x402-receipt \ --receipt-file receipt.json \ --write-evidence-file evidence.json
Signature requirements:
- Input must include
formatandsignatureon a signed offer-receipt envelope — typically underextensions.offer-receipt.info.receipt, or at the top level as{ "format", "payload", "signature" }. - JWS (
format: "jws"): compact serialization (header.payload.signature) with Ed25519 (EdDSA) or ES256; header must embed the verifyingjwk. - EIP-712 (
format: "eip712"): typed-data digest over the receipt payload fields with a secp256k1 signature (0x-prefixed 65-byte hex). - Raw unsigned receipt JSON is rejected.
Example JWS envelope (payload fields vary by vendor):
{ "extensions": { "offer-receipt": { "info": { "receipt": { "format": "jws", "signature": "<header>.<payload>.<sig>" } } } } }
Do not import Coinbase authorization_succeeded webhooks as evidence — those are funding, not completion.
Doctor alignment checks
paybond doctor warns (non-blocking) when:
- Local completion scaffold
evidence_schemadiverges from the catalog preset - Published tenant policy head parameters diverge from catalog defaults
- Scaffold properties intersect preset
forbidden_evidence_fields webhook_confirmedparameters use Stripe funding event types (payment_intent.succeeded,charge.succeeded)- Scaffold uses deprecated
stripe_webhook_payment - Vendor pack scaffold contract pins (
VENDOR_CONTRACT_API_VERSION, schema digests) lag the catalog (completion_pack_stale) - Vendor pack scaffold is missing
VENDOR_QUALITY_FIELDSexports (completion_quality_fields)
Contract pinning and drift
Vendor packs declare a frozen vendor_contract block in the catalog (api_version, schema digests, quality_fields). Harbor snapshots those fields on intent create and validates optional vendor_payload at evidence submit (signal-only — evidence is still accepted; drift surfaces in schema_validation and Signal).
| Workflow | Command / surface |
|---|---|
| Pre-validate locally | paybond policy validate-evidence --preset <id> --vendor-file vendor.json |
| Sandbox submit | Scaffolds pass vendorPayload alongside canonical payload via submitSandboxEvidence |
| Operator triage | Policy registry shows pinned vendor_contract; Signal emits COMPLETION_* drift codes |
| Integrator hygiene | paybond doctor warns when scaffold pins lag catalog |
paybond policy validate-evidence mirrors Harbor schema checks locally and additionally enforces preset forbidden_evidence_fields (rail-owned ids that must not appear in payee evidence). The JSON report includes:
| Field | Meaning |
|---|---|
vendor_schema_ok / canonical_schema_ok | JSON Schema conformance against frozen or live catalog schemas |
quality_fields_missing | Vendor-pack quality fields absent from the payload |
forbidden_fields_present | Rail-owned field names found in vendor or canonical evidence |
pack_stale | Frozen contract pins lag the live catalog |
drift_kinds | Machine-readable drift codes, including forbidden_field_present |
When forbidden_fields_present is non-empty, vendor_schema_ok and/or canonical_schema_ok are set to false and drift_kinds includes forbidden_field_present. Harbor submit still accepts evidence in v1 (signal-only); use this command in CI before agents submit.
Re-scaffold with paybond init completion --preset <id> --force after catalog api_version bumps. In-flight intents keep their frozen contract for audit.
Predicate VM scope is unchanged — archetypes compose existing ops only; array paths and regex are deferred until a template truly needs them.