AgentTrust
AgentTrust
Integration guides

x402 facilitator (generic)

Add AgentTrust decisions to any x402 facilitator without coupling to one vendor.

If you already accept x402 payment requests and want AgentTrust decisions before settlement, this is the guide. Generic shape — facilitator-specific quirks live in the adapter, not in the route layer.

If you're using Pay.sh, start there. If you're adding a new facilitator from scratch, start with the adapter contract.

Integration points

StepFacilitator actionAgentTrust call
1receive x402 request or retry proofFacilitatorAdapter.parseRequest
2translate into payer, payee, mint, amount, policy IDVerifyContext
3check policygate_payment simulation or gatePayment()
4return x402 denial or validation needadapter.formatChallenge
5settle paymentone signed transaction (gate + transfer + feedback)
6emit feedbackadapter.emitFeedback

Minimal Express mount

The published SDK is the easy path:

import express from "express";
import { Keypair } from "@solana/web3.js";
import { mountTrustGate } from "@agenttrust-sdk/trustgate/express";

const app = express();
app.use(express.json());

await mountTrustGate(app, {
  rpcUrl:             process.env.SOLANA_RPC_URL!,
  facilitatorKeypair: Keypair.fromSecretKey(/* facilitator key */),
  defaultPolicyId:    1,
  network:            "solana-devnet",
  atomicityEnforced:  true,
});

Routes added: POST /verify, POST /settle, POST /dispute, GET /receipt/:hash. Full reference: SDK → mountTrustGate.

Verify request shape

POST /verify
Content-Type: application/json

{
  "payerAgentAsset": "<base58 pubkey>",
  "payeeAgentAsset": "<base58 pubkey>",
  "amount":          "1000000",
  "mint":            "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
  "policyId":        1
}

For Pay.sh, the adapter reads this context from paymentRequirements.extra.agentTrust, verifies serviceSignature, derives paymentIdHash from extra.memo, and rejects mismatched payTo / payeeRecipient.

Denial response

HTTP/1.1 402 Payment Required
X-Agent-Trust-Decision: Deny
X-Payment-Required: denied
X-Payment-Reason-Code: 6
X-Payment-Reason-Name: CounterpartyTierBelowMin
X-Payment-Network: solana-devnet

Reason codes are stable: 1..15. Full table: Reference → DenyReason codes.

Validation response

HTTP/1.1 402 Payment Required
X-Agent-Trust-Decision: RequireValidation
X-Payment-Required: validation
X-Capability-Required: 366c075140aa69746625d4b733b55e267fc5c28387fd6d1c24901976ee3ddc42
X-Payment-Network: solana-devnet

The X-Capability-Required value is the 32-byte SHA-256 hash of the capability namespace name (e.g., kyc.tier-1.v1). Full lifecycle: Capability namespaces.

Settlement rule

The facilitator must keep the policy gate, token transfer, and feedback emission in one signed Solana transaction. The SDK enforces this via the atomicityEnforced: true literal-type guard. Splitting them silently corrupts VelocityLedger when a Token-2022 mint's TransferHook extension reverts the transfer. Full proof: Verification → Atomic-tx invariant.

Sources

FilePurpose
trustgate/server/src/x402.tsx402 wire envelope helpers
trustgate/sdk/src/express.tsPublished Express middleware
trustgate/server/src/facilitators/Per-facilitator adapter implementations

On this page

⌘I