This page documents the public TypeScript SDK. Use it when you need the exact method signatures, result shapes, and error classes exposed by @paybond/kit.
For a first paid-tool guardrail integration, start with One-command guardrails. For a guided production integration, use the TypeScript quickstart. For the underlying HTTP contract, use the Harbor API reference and API documentation.
This SDK currently covers the Harbor application lifecycle, tenant-scoped ledger reads, protocol helpers, A2A discovery, read-only tenant-bound Signal reads, fraud review surfaces, and the packaged MCP server.
Package and runtime
@paybond/kit is an ESM-only package for Node.js 22+ and compatible bundlers. The root package export is the SDK surface documented below:
npm install @paybond/kit
The package also exposes:
@paybond/kit/mcp-server— programmatic MCP server classes and settings helpers.paybond— the packaged CLI;paybond loginstarts sandbox device approval and writesPAYBOND_API_KEYto.env.local.paybond-mcp-server— the packaged stdio MCP server binary.paybond-init— a scaffold command for Paybond guardrail integration helpers.
Module entry point
import {
Paybond,
PaybondGuardrails,
PaybondCapabilityBinding,
PaybondSpendGuard,
PaybondSpendDeniedError,
PaybondIntents,
authorizeSpend,
guardTool,
paybondAgentToolSpendGuard,
paybondRuntimeNeutralToolSpendGuard,
paybondRuntimeToolCallAdapter,
paybondLangGraphToolSpendGuard,
paybondMCPToolSpendGuard,
ServiceAccountSignalSession,
ServiceAccountFraudSession,
GatewayHarborClient,
HarborClient,
GatewaySignalClient,
GatewayFraudClient,
GatewayA2AClient,
GatewayProtocolClient,
HarborHttpError,
GatewayAuthError,
SignalHttpError,
A2AHttpError,
ProtocolHttpError,
type SettlementRail,
type FundIntentResult,
type IntentFundingResult,
type SandboxGuardrailBootstrapResult,
type SandboxGuardrailEvidenceResult,
type SubmitEvidenceResult,
type VerifyCapabilityResult,
type A2AAgentCard,
type A2ATaskContractCatalogV1,
type A2ASettlementTaskContractV1,
type AgentMandateV1,
type SignedAgentMandateV1,
type AgentRecognitionProofV1,
type ProtocolTransportBindingV1,
type ProtocolAuthorizationReceiptV1,
type ProtocolSettlementReceiptV1,
type ImportAgentMandateV1Result,
type VerifyProtocolReceiptV1Result,
// low-level helpers
buildSignedCreateIntentBody,
intentCreationSignBytesRaw,
signPayeeEvidenceBinding,
artifactsDigest,
normalizeJson,
jsonValueDigest,
} from "@paybond/kit";
MCP is a subpath export:
import {
PaybondMCPServer,
settingsFromEnv,
main as runPaybondMCPServer,
type PaybondMCPSettings,
} from "@paybond/kit/mcp-server";
High-level client
Paybond.open
static Paybond.open(init: {
apiKey: string; // "paybond_sk_live_…" or "paybond_sk_sandbox_…" service-account key
expectedEnvironment?: "live" | "sandbox";
maxRetries?: number; // default 3
}): Promise<Paybond>;
Resolves the service-account principal at the hosted Gateway, caches the echoed tenant_id, and returns a Paybond instance bound to that tenant realm. Hosted integrations only need apiKey.
Set expectedEnvironment to fail fast when a deployment is accidentally pointed at a live key from sandbox, or a sandbox key from live.
Throws GatewayAuthError on any tenant-principal lookup or credential failure. Response body text is redacted only by you at log time; avoid logging raw credential diagnostics.
Tenant isolation: the returned session is bound to the Gateway-derived tenant_id. Do not reuse the instance across tenants — build one per (tenant, service account).
Paybond instance
class Paybond {
readonly harbor: GatewayHarborClient; // tenant-bound Gateway Harbor surface
readonly signal: GatewaySignalClient; // tenant-bound Signal reads
readonly fraud: GatewayFraudClient; // tenant-bound fraud reads and review events
readonly a2a: GatewayA2AClient; // A2A discovery reads
readonly protocol: GatewayProtocolClient; // protocol-v2 and recognition-gated helpers
readonly guardrails: PaybondGuardrails; // sandbox-only first guardrail helpers
readonly intents: PaybondIntents; // ergonomic intent helpers
authorizeSpend(input: {
intentId: string;
token: string;
operation: string;
requestedSpendCents?: number;
}): Promise<VerifyCapabilityResult>;
spendGuard(intentId: string, capabilityToken: string): PaybondSpendGuard;
aclose(): Promise<void>;
}
paybond.harbor— the tenant-bound Gateway-backed Harbor surface. Use it for capability verification and recognition-gated Harbor proxy calls.paybond.signal— the tenant-boundGatewaySignalClient.paybond.fraud— the tenant-boundGatewayFraudClient.paybond.a2a— theGatewayA2AClientfor A2A discovery.paybond.protocol— the tenant-boundGatewayProtocolClientfor protocol-v2 receipts, mandate import, and recognition-gated gateway mutations.paybond.guardrails— the sandbox-onlyPaybondGuardrailsclient for first paid-tool guardrail integration.paybond.intents— seePaybondIntents.paybond.aclose()— release HTTP resources. Always await in afinallyblock.
PaybondGuardrails
paybond.guardrails wraps the Free Developer sandbox guardrail routes. These routes derive tenant scope from the service-account API key, reject caller-supplied tenant IDs, and use simulator settlement only.
paybond.guardrails.bootstrapSandbox(input: {
operation: string;
requestedSpendCents: number;
currency?: string;
evidenceSchema?: Record<string, unknown>;
metadata?: Record<string, unknown>;
idempotencyKey?: string;
}): Promise<SandboxGuardrailBootstrapResult>;
paybond.guardrails.submitSandboxEvidence(input: {
intentId: string;
payload?: Record<string, unknown>;
artifacts?: string[];
operation?: string;
requestedSpendCents?: number;
metadata?: Record<string, unknown>;
idempotencyKey?: string;
}): Promise<SandboxGuardrailEvidenceResult>;
Both result types include tenant_id, intent_id, operation, requested_spend_cents, and sandbox_lifecycle_status; bootstrap also returns the capability_token used with paybond.spendGuard(...).
PaybondIntents
paybond.intents wraps the principal/payee signing flows plus x402 funding. All methods derive tenant scope from the bound Harbor client; callers never pass a tenant id.
paybond.intents.create
paybond.intents.create(params: {
principalDid: string;
principalSigningSeed: Uint8Array; // exactly 32 bytes
recognitionProof: AgentRecognitionProofV1 | Record<string, unknown>;
payeeDid: string;
budget: Record<string, unknown>; // canonical JSON (e.g. { currency, max_spend_usd })
predicate: Record<string, unknown>; // predicate_dsl (version 1 and root node)
currency: string;
amountCents: number;
evidenceSchema: Record<string, unknown>; // JSON schema for evidence payloads
deadlineRfc3339: string;
allowedTools: string[];
predicateRef?: string; // managed-policy digest when set
settlementRail: SettlementRail; // principal-signed rail request; destination stays server-owned
intentId?: string; // defaults to crypto.randomUUID()
idempotencyKey?: string;
}): Promise<Record<string, unknown>>;
Builds a principal-signed intent body via buildSignedCreateIntentBody, applies BLAKE3 digests to canonical JSON for budget, evidence_schema, and predicate_dsl, and POSTs it through Gateway POST /harbor/intents.
paybond.intents.createSpendIntent(params) is a spend-oriented alias for the same method. Use it in agent-facing code when the user asked for agent spend controls, delegated spend guardrails, or tool-call budget checks.
Retries honor idempotencyKey on transient 5xx/429. Reusing a key with a different body returns HTTP 409 from Harbor (see docs/api/harbor-idempotency-openapi.yaml).
allowedTools is a caller-defined allow-list of delegated operation names such as travel.planner.plan or crm.contact.enrich. Paybond does not define these strings; Harbor only checks that later verify calls use a matching value.
settlementRail is required and included in the principal signature. It requests one allowed rail for the new intent. Harbor validates it against the tenant's canonical settlement config, resolves the destination server-side, and snapshots the effective routing onto the intent.
paybond.intents.fund
paybond.intents.fund(params: {
intentId: string;
recognitionProof: AgentRecognitionProofV1 | Record<string, unknown>;
paymentSignature?: string;
idempotencyKey?: string;
}): Promise<FundIntentResult>;
Advances Gateway POST /harbor/intents/{intent_id}/fund for x402_usdc_base intents. Returns structured 402 challenges (paymentRequired), 202 pending states, and 200 funded results without forcing callers to catch those statuses as exceptions.
paybond.intents.submitEvidence
paybond.intents.submitEvidence(params: {
intentId: string;
payeeDid: string;
payeeSigningSeed: Uint8Array; // exactly 32 bytes
recognitionProof: AgentRecognitionProofV1 | Record<string, unknown>;
payload: Record<string, unknown>; // evidence JSON matching the intent's schema
artifactsBlake3Hex?: string[]; // default []
submittedAtRfc3339?: string; // default current UTC second
idempotencyKey?: string;
}): Promise<SubmitEvidenceResult>;
Signs the payee binding via signPayeeEvidenceBinding and POSTs it through Gateway POST /harbor/intents/{intent_id}/evidence.
Gateway-backed Harbor mutations require a replay-safe recognition proof bound to the exact method, path, purpose, tenant, and request body.
The high-level helper defaults artifactsBlake3Hex to [] and submittedAtRfc3339 to the current UTC second. The low-level signPayeeEvidenceBinding helper still requires concrete values because they are part of the signed bytes.
The response includes state, tenant, and an optional predicatePassed boolean; a false here is not an HTTP error — the predicate evaluation failed and the intent moved to evidence_submitted with the recorded failure.
Verify (Gateway-enriched)
The Kit exposes capability verification on the underlying Harbor client rather than on paybond.intents. On hosted Gateway sessions, POST /verify runs Harbor capability validation first, then applies tenant spend policy before returning the final allow/deny outcome.
paybond.harbor.verifyCapability({
intentId: string;
token: string; // base64 Biscuit token
operation: string; // e.g. "travel.book_hotel"
requestedSpendCents?: number; // default 0
vendorId?: string;
taskId?: string;
workflowId?: string;
toolCallId?: string;
toolName?: string;
currency?: string;
agentSubject?: string;
approvalToken?: string; // short-lived token after operator approval
idempotencyKey?: string;
}): Promise<VerifyCapabilityResult>;
Pass vendor, task, workflow, tool, and agent metadata when tenant spend policy evaluates rolling caps, anomaly rules, or approval thresholds against those scopes. After an operator approves a held request in the console, retry with the same operation, amount, and metadata plus approvalToken.
Returns HTTP 200 with allow: false when Harbor or Gateway denies — that is not thrown as an error. When Gateway policy requires human approval first, the response includes approvalRequired: true and usually decisionId / approvalRequestId; handle that separately from a hard policy denial (see PaybondSpendGuard).
Confirm settlement
Settlement confirmation is an operator-tier action and is not wrapped by paybond.intents. For protocol-driven flows, use the recognition-gated paybond.protocol.confirmHarborSettlement helper:
await paybond.protocol.confirmHarborSettlement({
intentId,
body: {}, // Harbor derives release/refund from the recorded predicate result.
recognitionProof,
idempotencyKey: settlementIdempotencyKey,
});
The helper calls the Gateway /harbor/intents/{intent_id}/settlement/confirm route with x-tenant-id and x-paybond-agent-recognition-proof. Gateway still enforces the protocol recognition proof, tenant scope, and operator/administrative policy. Harbor does not let this route choose release or refund; it confirms the settlement action implied by the evidence evaluation already stored on the intent. Prefer the Operator Console for human-reviewed settlement.
Gateway Harbor client
class GatewayHarborClient {
constructor(gatewayBaseUrl: string, tenantId: string, options: {
staticGatewayBearerToken: string;
maxRetries?: number;
});
readonly tenantId: string;
verifyCapability(input: PaybondSpendAuthorizationInput & {
intentId: string;
token: string;
}): Promise<VerifyCapabilityResult>;
/** Finalize active scope reservations after tool execution completes or is aborted. */
completeSpendDecision(input: {
decisionId: string;
outcome: "consumed" | "released";
}): Promise<void>;
createIntent(body: Record<string, unknown>, options: {
recognitionProof: AgentRecognitionProofV1 | Record<string, unknown>;
idempotencyKey?: string;
}): Promise<Record<string, unknown>>;
}
Paybond.open(...) constructs this for hosted integrations. Build it directly only when you already have a trusted tenant id from Gateway principal introspection.
HarborClient
Tenant-bound async HTTP client. Sends x-tenant-id on every request; verifies Harbor echoes the same tenant and the requested intent_id on POST /verify (confused-deputy hardening).
class HarborClient {
constructor(harborBase: string, tenantId: string, options?: {
harborBearerSupplier?: () => Promise<string | null | undefined>;
staticHarborBearerToken?: string;
maxRetries?: number;
});
readonly tenantId: string;
verifyCapability(input: {
intentId: string;
token: string;
operation: string;
requestedSpendCents?: number;
}): Promise<VerifyCapabilityResult>; // harborVerifyCapability
createIntent(
body: Record<string, unknown>,
options?: { idempotencyKey?: string },
): Promise<Record<string, unknown>>; // harborCreateIntent
fundIntent(
intentId: string,
options?: { paymentSignature?: string; idempotencyKey?: string },
): Promise<FundIntentResult>; // harborFundIntent
submitEvidence(
intentId: string,
evidenceBody: Record<string, unknown>,
options?: { idempotencyKey?: string },
): Promise<SubmitEvidenceResult>; // harborSubmitEvidence
getLedgerTip(): Promise<Record<string, unknown>>;
getLedgerAuthority(): Promise<Record<string, unknown>>;
getLedgerEvents(options?: { afterSeq?: number; limit?: number }): Promise<Record<string, unknown>>;
getLedgerMerkleLatest(): Promise<Record<string, unknown>>;
}
Retries 429 / 500 / 502 / 503 / 504 with exponential backoff and jitter, honoring a bounded Retry-After. All other 4xx/5xx throw HarborHttpError.
FundIntentResult
Structured return type for paybond.intents.fund(...) and harbor.fundIntent(...).
statusCode:402,202, or200paymentRequired: x402 challenge header whenstatusCode === 402paymentResponse: optional Coinbase receipt header on202or200intentId,tenant,statesettlementRail,currency,amountCentsfunded: whether Harbor has transitioned the intent into the funded statefunding: optionalIntentFundingResultcapabilityToken: present when Harbor already minted the funded capability
IntentFundingResult
Normalized Harbor funding payload fields:
settlementRailharborFundEndpointstatuspaymentSessionIdpaymentUrlstripePaymentIntentId,clientSecret,stripeConnectDestinationstripeCustomerId,latestChargeId,paymentMethodId,mandateIdfinancialConnectionsAccountId,bankLast4,bankFingerprint,bankNameasset,networkauthorizationId,captureId,voidId,transferId,refundIdexpectedDebitDate,paymentReference,refundReference,refundReferenceStatussourceAddress,targetAddressauthorizationExpiresAt,captureExpiresAt,refundExpiresAtonchainTransactionHashes
SettlementRail
type SettlementRail = "stripe_connect" | "stripe_ach_debit" | "x402_usdc_base";
Public type alias for the only supported client-requestable settlement rails. The SDK does not expose any client-side destination fields; Harbor resolves destinations from tenant-owned settlement config.
Ledger reads
The SDK includes protected tenant-scoped provenance reads on the low-level direct HarborClient. Hosted Paybond.open(...) integrations should prefer Gateway's public compliance surface, verifier packs, verification results, and audit exports instead of a raw ledger event stream.
getLedgerTip()→GET /ledger/v1/tipgetLedgerAuthority()→GET /ledger/v1/authoritygetLedgerEvents({ afterSeq, limit })→GET /ledger/v1/eventsgetLedgerMerkleLatest()→GET /ledger/v1/merkle/latest
Each method validates the echoed tenant_id against the bound client tenant and fails closed on mismatch.
Signal reads
The TypeScript SDK ships a tenant-bound gateway Signal client for the supported read-only V1.0.1 surfaces.
GatewaySignalClient
class GatewaySignalClient {
constructor(gatewayBaseUrl: string, tenantId: string, options: {
staticGatewayBearerToken: string;
maxRetries?: number;
});
readonly tenantId: string;
getReputationReceipt(
operatorDid: string,
scoreVersion?: string,
): Promise<SignalReceiptEnvelope | null>;
getPortfolioSummary(scoreVersion?: string): Promise<SignalPortfolioSummary>;
getSignedPortfolioArtifact(
scoreVersion?: string,
): Promise<SignalSignedPortfolioArtifact>;
getOperatorExplanation(
operatorDid: string,
scoreVersion?: string,
): Promise<Record<string, unknown> | null>;
getOperatorReviewStatus(
operatorDid: string,
scoreVersion?: string,
): Promise<Record<string, unknown> | null>;
}
This client validates the echoed tenant_id and operator_did on every response. 404 remains a null result for receipt, explanation, and review-status lookups; other non-success statuses throw SignalHttpError. getSignedPortfolioArtifact() returns the tenant-scoped signed portfolio export that partner verifiers can carry between systems without exposing a shared public leaderboard surface.
ServiceAccountSignalSession
class ServiceAccountSignalSession {
static open(init: {
gatewayBaseUrl: string;
apiKey: string;
principalPath?: string; // default "/v1/auth/principal"
expectedEnvironment?: "live" | "sandbox";
maxRetries?: number;
}): Promise<ServiceAccountSignalSession>;
readonly signal: GatewaySignalClient;
aclose(): Promise<void>;
}
This is the easiest tenant-safe path for partner developers who only need Signal reads. The session resolves the tenant from GET /v1/auth/principal using the same service-account credential instead of relying on ad hoc tenant headers.
Fraud review and metrics
GatewayFraudClient
class GatewayFraudClient {
constructor(gatewayBaseUrl: string, tenantId: string, options: {
staticGatewayBearerToken: string;
maxRetries?: number;
});
readonly tenantId: string;
getFraudAssessment(
operatorDid: string,
scoreVersion?: string,
): Promise<SignalFraudAssessmentResponse | null>;
listFraudReviewQueue(options?: {
state?: "none" | "open" | "in_review" | "closed" | "all" | string;
severity?: "elevated" | "high" | "critical" | string;
limit?: number;
scoreVersion?: string;
}): Promise<SignalFraudReviewQueueResponse>;
getFraudMetrics(options?: {
window?: "24h" | "7d" | "30d" | string;
scoreVersion?: string;
}): Promise<SignalFraudMetricsResponse>;
getFraudReleaseGateConfig(scoreVersion?: string): Promise<SignalFraudReleaseGateConfigResponse>;
setFraudReleaseGateMode(
mode: "review_only" | "critical_hold" | string,
): Promise<SignalFraudReleaseGateConfigResponse>;
recordFraudReviewEvent(
operatorDid: string,
event: {
eventType: "review_open_requested" | "appeal_requested" | "replay_requested" | "review_outcome_recorded" | "confirmed_risk" | "false_positive" | "needs_more_evidence";
reviewOutcome?: "confirmed_risk" | "false_positive" | "needs_more_evidence";
signalCode?: string;
intentId?: string;
providerEventId?: string;
summary: string;
},
scoreVersion?: string,
): Promise<SignalFraudReviewEventResponse>;
}
The fraud client validates echoed tenant_id and, for operator-scoped methods, operator_did. SignalFraudMetricsResponse includes rolling-window backtest and monitoring fields such as false_positive_rate_bps, labeled_coverage_bps, critical_signal_hold_candidate_count, stale_label_gap_seconds, stale_signal_family_label_gap_count, and backtest_summary. SignalFraudSignal preserves the fraud_signal_version=1.0.7 additive metadata fields signal_source, first_seen_at, last_seen_at, evidence_binding_strength, provider_event_refs, and intent_refs when Gateway returns them. setFraudReleaseGateMode() accepts only review_only or critical_hold; Gateway still enforces tenant-admin access and keeps review_only as the default. recordFraudReviewEvent() only accepts review workflow/outcome event types, does not expose settlement or money-movement events, and can pass optional signal-level feedback context through signalCode, intentId, and providerEventId.
ServiceAccountFraudSession
class ServiceAccountFraudSession {
static open(init: {
gatewayBaseUrl: string;
apiKey: string;
principalPath?: string; // default "/v1/auth/principal"
expectedEnvironment?: "live" | "sandbox";
maxRetries?: number;
}): Promise<ServiceAccountFraudSession>;
readonly fraud: GatewayFraudClient;
aclose(): Promise<void>;
}
Paybond.open(...) also exposes gateway clients as paybond.signal, paybond.fraud, paybond.a2a, and paybond.protocol.
A2A discovery
GatewayA2AClient
class GatewayA2AClient {
constructor(gatewayBaseUrl: string, options?: {
staticGatewayBearerToken?: string;
maxRetries?: number;
});
getAgentCard(): Promise<A2AAgentCard>;
getTaskContracts(): Promise<A2ATaskContractCatalogV1>;
getTaskContract(contractId: string): Promise<A2ASettlementTaskContractV1>;
}
paybond.a2a is created automatically by Paybond.open and carries the same service-account bearer token when available. Use it for:
GET /.well-known/agent-card.jsonGET /protocol/v2/a2a/task-contractsGET /protocol/v2/a2a/task-contracts/{contract_id}
Non-success statuses throw A2AHttpError. See Agent integrations and V2 protocol trust.
Protocol v2 and recognition-gated gateway mutations
GatewayProtocolClient
class GatewayProtocolClient {
constructor(gatewayBaseUrl: string, tenantId: string, init?: {
staticGatewayBearerToken?: string;
maxRetries?: number;
});
readonly tenantId: string;
importAgentMandateV1(init: {
signedMandate: SignedAgentMandateV1;
intentId: string;
transportBinding?: ProtocolTransportBindingV1;
recognitionProof: AgentRecognitionProofV1 | Record<string, unknown>;
}): Promise<ImportAgentMandateV1Result>;
getSettlementReceiptV1(receiptId: string): Promise<ProtocolSettlementReceiptV1>;
verifyProtocolReceiptV1(
receipt: ProtocolAuthorizationReceiptV1 | ProtocolSettlementReceiptV1 | Record<string, unknown>,
): Promise<VerifyProtocolReceiptV1Result>;
createHarborIntent(init: {
body: Record<string, unknown>;
recognitionProof: AgentRecognitionProofV1 | Record<string, unknown>;
idempotencyKey?: string;
}): Promise<Record<string, unknown>>;
fundHarborIntent(init: {
intentId: string;
recognitionProof: AgentRecognitionProofV1 | Record<string, unknown>;
paymentSignature?: string;
idempotencyKey?: string;
}): Promise<Record<string, unknown>>;
submitHarborEvidence(init: {
intentId: string;
body: Record<string, unknown>;
recognitionProof: AgentRecognitionProofV1 | Record<string, unknown>;
idempotencyKey?: string;
}): Promise<Record<string, unknown>>;
confirmHarborSettlement(init: {
intentId: string;
body: Record<string, unknown>; // usually {}; included in the recognition envelope
recognitionProof: AgentRecognitionProofV1 | Record<string, unknown>;
idempotencyKey?: string;
}): Promise<Record<string, unknown>>;
}
paybond.protocol is created automatically by Paybond.open. It sends x-tenant-id, adds authorization when a gateway bearer token is configured, and base64url-encodes the recognition proof into x-paybond-agent-recognition-proof for recognition-gated Harbor mutation helpers.
Paybond is AP2-aligned at the protocol boundary. On mandate import, transportBinding.source_protocol is optional and Gateway defaults it to ap2 for imported external mandates and exported protocol receipts.
Gateway HTTP failures throw ProtocolHttpError with parsed errorCode / errorMessage when Gateway returns a JSON error envelope. Tenant, intent, and receipt echo mismatches throw plain Error and should be treated as critical tenant-isolation failures.
Core protocol types
The SDK exports the protocol shapes used by GatewayProtocolClient:
AgentMandateV1/SignedAgentMandateV1AgentRecognitionProofV1ProtocolTransportBindingV1ProtocolAuthorizationReceiptV1ProtocolSettlementReceiptV1ImportAgentMandateV1ResultVerifyProtocolReceiptV1Result
MCP server subpath
type PaybondMCPSettings = {
apiKey: string;
gatewayBaseUrl?: string;
principalPath?: string;
maxRetries?: number;
};
class PaybondMCPServer {
constructor(settings: PaybondMCPSettings);
listTools(): Array<Record<string, unknown>>;
callTool(name: string, args?: Record<string, unknown>): Promise<{
content: Array<{ type: "text"; text: string }>;
structuredContent?: Record<string, unknown>;
isError?: boolean;
}>;
handleMessage(message: Record<string, unknown>): Promise<Record<string, unknown> | null>;
runStdio(): void;
}
settingsFromEnv(env?: Record<string, string | undefined>): PaybondMCPSettings;
runPaybondMCPServer(argv?: string[]): number;
The packaged binary is usually simpler:
npx paybond-mcp-server
Required environment is PAYBOND_API_KEY. See the MCP server guide for the supported tool list and host configuration.
PaybondCapabilityBinding
Most application code should use paybond.spendGuard(intentId, capabilityToken) instead. This
class remains the lower-level backing type for callers that need to build their own guard wrapper.
class PaybondCapabilityBinding {
constructor(
readonly harbor: HarborClient,
readonly intentId: string,
readonly capabilityToken: string,
);
verifySpendCapability(input: {
operation: string;
requestedSpendCents?: number;
}): Promise<VerifyCapabilityResult>;
authorizeSpend(input: {
operation: string;
requestedSpendCents?: number;
}): Promise<VerifyCapabilityResult>;
}
Binds (harbor, intentId, capabilityToken) so agent tool wrappers have a single tenant-safe handle to verify against. See the Capabilities guide and the verify walkthrough.
PaybondSpendGuard
const guard = paybond.spendGuard(intentId, capabilityToken);
const guardedTool = guard.guardTool(
{
operation: "travel.book_hotel",
requestedSpendCents: 20_000,
vendorId: "vendor_acme",
toolName: "travel.book_hotel",
agentSubject: "agent:ops-bot",
},
async (input) => bookHotel(input),
);
PaybondSpendGuard is a discoverable wrapper around Gateway-enriched capability verification. It calls verifyCapability before the handler runs:
- throws
PaybondSpendDeniedErroron hard denials (allow: falsewithout approval required) - throws
PaybondSpendApprovalRequiredErrorwhen Gateway returnsapprovalRequired: true - after a successful authorization,
guardToolruns the handler and then callscompleteSpendDecisionwith outcomeconsumedon success orreleasedwhen the handler throws (best-effort release)
If you call authorizeSpend or assertSpendAuthorized directly instead of guardTool, call completeSpendAuthorization yourself when the guarded work finishes or aborts.
Standalone helpers are also exported. They accept either a PaybondSpendGuardInit
object ({ harbor, intentId, capabilityToken }) or the lower-level
PaybondCapabilityBinding:
authorizeSpend(source, input)guardTool(source, input, handler)paybondAgentToolSpendGuard(source, input, handler)paybondRuntimeNeutralToolSpendGuard(source, input, handler)paybondLangGraphToolSpendGuard(source, input, handler)paybondMCPToolSpendGuard(source, input, handler)
PaybondSpendAuthorizationInput fields: operation, requestedSpendCents, vendorId, taskId, workflowId, toolCallId, toolName, currency, agentSubject, approvalToken, idempotencyKey.
For agent SDKs or custom runtimes that hand your application a tool-call object and an executor,
use paybondRuntimeToolCallAdapter(...):
const runTool = paybondRuntimeToolCallAdapter({
source: { harbor: paybond.harbor, intentId, capabilityToken },
operation: (call) => call.name,
requestedSpendCents: (call) => call.spendCents,
execute: executeToolCall,
onDeny: (result) => ({ status: "blocked", reason: result.message ?? result.code }),
});
Scaffolding
Sandbox credential setup:
npx -p @paybond/kit paybond login
The login command supports --env-file, --gateway, --no-open, and --force. It writes .env.local with mode 0600, adds the default .env.local target to .gitignore when needed, refuses custom unignored env files inside git repos, and prints only masked key identity plus the target sandbox tenant.
npx -p @paybond/kit paybond-init \
--preset paid-tool-guard \
--framework provider-agnostic \
--out paybond-paid-tool-guard.ts
Supported framework labels are generic, provider-agnostic, openai, claude, anthropic, gemini, google-ai, vercel-ai, langgraph, and mcp. The scaffold writes reusable guardrail helpers and expects your application to provide the paid-tool handler; it does not manage signing keys or payment wallets.
Result types
VerifyCapabilityResult
Gateway-enriched verify outcome. Harbor-only deployments populate the core fields; hosted Gateway sessions may also return spend-policy metadata.
type VerifyCapabilityResult = {
allow: boolean;
auditId: string;
tenant: string;
intentId: string;
code?: string;
message?: string;
decisionId?: string;
approvalRequestId?: string;
policyVersion?: number;
reasonCodes?: string[];
spendScope?: { scope_type: string; scope_key: string };
remainingCents?: number;
retryAfter?: number;
/** True when tenant policy requires operator approval before execution may proceed. */
approvalRequired?: boolean;
};
| Field | Meaning |
|---|---|
allow | Final authorization decision after Harbor capability checks and Gateway spend policy. |
approvalRequired | Policy hold — not a hard deny. Surface to operators and retry with approvalToken after approval. |
decisionId | Immutable authorization decision id; used to finalize scope reservations after tool execution. |
approvalRequestId | Pending approval queue item when quorum is incomplete. |
reasonCodes | Machine-readable policy outcomes (for example approval_threshold_exceeded, daily_tenant_cap_exceeded). |
spendScope / remainingCents | Scope that governed the check and optional remaining budget headroom. |
PaybondSpendDeniedError / PaybondSpendApprovalRequiredError
PaybondSpendGuard.assertSpendAuthorized and guardTool raise PaybondSpendDeniedError when allow is false and approval is not required. They raise PaybondSpendApprovalRequiredError when approvalRequired is true. Both errors expose a result: VerifyCapabilityResult property for logging and operator UX.
SubmitEvidenceResult
type SubmitEvidenceResult = {
intentId: string;
tenant: string;
state: string;
predicatePassed?: boolean;
};
ImportAgentMandateV1Result
type ImportAgentMandateV1Result = {
valid: boolean;
intent_id: string;
mandate_digest_sha256_hex: string;
mandate: AgentMandateV1;
authorization_receipt: ProtocolAuthorizationReceiptV1;
};
Returned by GatewayProtocolClient.importAgentMandateV1. The client verifies the echoed intent_id and mandate tenant before returning.
VerifyProtocolReceiptV1Result
type VerifyProtocolReceiptV1Result = {
valid: boolean;
kind: string;
receipt_id: string;
tenant_id: string;
receipt: ProtocolAuthorizationReceiptV1 | ProtocolSettlementReceiptV1 | Record<string, unknown>;
};
Returned by GatewayProtocolClient.verifyProtocolReceiptV1 for authorization and settlement receipt verification.
Canonical signing helpers
These helpers are intended for advanced callers that build signed request bodies or evidence payloads outside of paybond.intents. They match Paybond's canonical signing rules byte-for-byte.
buildSignedCreateIntentBody
buildSignedCreateIntentBody(params: BuildSignedCreateIntentParams): Record<string, unknown>;
Builds a signed CreateIntentRequest body for operation harborCreateIntent. Canonical JSON normalization is applied before BLAKE3 digesting and Ed25519 signing.
params.settlementRail is signed into the create-intent payload and only includes the requested rail name. No SDK surface accepts free-form Stripe destinations or x402 receive addresses.
intentCreationSignBytesRaw
intentCreationSignBytesRaw(params: BuildSignedCreateIntentParams): Uint8Array;
Returns the exact bytes that get Ed25519-signed. Useful for offline signers (for example HSMs or air-gapped principal keys).
signPayeeEvidenceBinding
signPayeeEvidenceBinding(params: SignPayeeEvidenceParams): Record<string, unknown>;
Builds a signed evidence wire body for operation harborSubmitEvidence.
artifactsDigest, normalizeJson, jsonValueDigest
BLAKE3-based helpers that match the canonical rules used by Harbor. Exported for offline verification tooling.
Typed errors
All error classes extend Error and attach structured diagnostics instead of wrapping an opaque unknown. Never log raw tokens or API keys; the Kit redacts nothing itself — redaction is a caller responsibility.
HarborHttpError
class HarborHttpError extends Error {
readonly statusCode: number;
readonly url: string;
readonly bodyText: string; // raw Harbor response body (may be JSON)
}
Thrown by HarborClient when Harbor returns any non-success status after retries. Look for the machine-readable code field inside bodyText — contracts are in the Error envelope reference.
A2AHttpError
class A2AHttpError extends Error {
readonly statusCode: number;
readonly url: string;
readonly bodyText: string;
}
Thrown by GatewayA2AClient when A2A discovery routes return non-success statuses after retries.
ProtocolHttpError
class ProtocolHttpError extends Error {
readonly statusCode: number;
readonly url: string;
readonly bodyText: string; // raw gateway response body (may be JSON)
readonly errorCode?: string; // parsed gateway "error" field when present
readonly errorMessage?: string; // parsed gateway "message" field when present
}
Thrown by GatewayProtocolClient and paybond.protocol for gateway-backed protocol/v2/* calls plus recognition-gated gateway /harbor/* mutation helpers. The Kit parses JSON gateway error envelopes so callers can branch on explicit codes such as unregistered_key, tenant_mismatched_key, revoked_key, mandate_agent_key_mismatch, and protocol_binding_mismatch without reparsing bodyText.
GatewayAuthError
class GatewayAuthError extends Error {
readonly statusCode: number | undefined;
readonly bodyText: string | undefined;
}
Thrown when Gateway rejects the API key, returns malformed JSON, or omits tenant_id.
SignalHttpError
class SignalHttpError extends Error {
readonly statusCode: number;
readonly url: string;
readonly bodyText: string;
}
Thrown by GatewaySignalClient when gateway Signal routes return a non-success status after retries, excluding the 404 -> null read contract on receipt, explanation, and review-status lookups.
Tenant, intent, and receipt mismatch
HarborClient, GatewaySignalClient, GatewayFraudClient, and GatewayProtocolClient throw plain Error instances when Harbor or Gateway echoes a different tenant, intent, operator, mandate, or receipt than requested. Treat these as critical tenant-isolation failures and do not retry.
Retries, idempotency, and logging
- All mutating POSTs accept
idempotencyKey. The same key with the same body is safe to retry on transient failures; the same key with a different body returns409. - Log
tenant_id,intent_id,statusCode,url, correlation id (when present), and a redactedbodyText. Never log the API key, Harbor JWT, or capability token. - Backoff is exponential with jitter, bounded at ~5s per attempt;
Retry-Afteris honored up to 30s.