Quickstart

From zero to settled in 5 minutes.

Each scenario is self-contained — it creates its own mint, merchant, attestor, and agent on Solana devnet. The hosted API and demo expose the same headless settlement path on public devnet services.

Prerequisites

  • solana-cli 2.0+ pointing at devnet
  • anchor 0.31.1
  • bun 1.3+
  • ≥ 0.5 SOL on the configured wallet (devnet airdrop is fine)
solana config set -u devnet
solana balance        # >= 0.5 SOL
solana airdrop 2      # if low

Install

git clone <aap repo>
cd aap
bun install
bun run --filter @aap/shared-types build
bun run --filter @aap/sdk-ts build
cd contracts && anchor build

One-command x402 demo

The fastest end-to-end proof starts the demo merchant, waits for it to become healthy, runs the agent CLI, creates escrow, hits the paywalled endpoint, and confirms final settlement.

ANCHOR_PROVIDER_URL=https://api.devnet.solana.com \
ANCHOR_WALLET=~/.config/solana/id.json \
bun run demo:e2e

Override TARGET_URL or MERCHANT_URL if you want to point the demo at a different page or an already-running merchant server.

Hosted API and demo

The public demo is split into a visual merchant harness and a headless API. Use the root API URL when you want the console; use /v1/* endpoints when an agent needs JSON.

open https://demo.settleproof.xyz
open https://api.settleproof.xyz

curl -s https://api.settleproof.xyz/v1/status
curl -s 'https://api.settleproof.xyz/v1/indexer?limit=5'
curl -s https://api.settleproof.xyz/v1/relay

Hosted smoke test

Before a demo, run the hosted smoke script. It checks the landing, docs, OpenAPI, API status, escrow preparation, persistent indexer, demo health, and x402 challenge path.

bun run smoke:hosted

# optional overrides
SITE_URL=https://settleproof.xyz \
API_URL=https://api.settleproof.xyz \
DEMO_URL=https://demo.settleproof.xyz \
bun run smoke:hosted

Scenario 1 — Release (happy path)

Agent pays, merchant delivers and signs an attestation off-chain, on-chain CPI verifies the signature, USDC transfers to the merchant.

cd packages/sdk-ts
ANCHOR_PROVIDER_URL=https://api.devnet.solana.com \
ANCHOR_WALLET=~/.config/solana/id.json \
bun run examples/scenario-1-release.ts
[1] Setup: mint USDC mock + fund agent/merchant
[2] Init registry + register merchant
[3] Mint USDC to agent + create ATAs
[4] Agent createEscrow → vault custodies 1 USDC
[5] Merchant signAttestation off-chain (Ed25519)
[6] releaseEscrow on-chain → CPI verify_attestation → transfer
[7] Verify final balances
    ✓ merchant: 1 USDC ← released
    ✓ vault:    0 USDC ← drained
    ✓ escrow state: fulfilled
✓ Scenario 1 complete — USDC released to merchant

Scenario 2 — TTL refund (auto dispute)

Agent pays, merchant fails to deliver and never attests. After TTL, anyone can call claim_refund and the funds return to the agent owner. No chargeback, no human arbitration.

bun run examples/scenario-2-refund.ts
[3] Agent createEscrow with TTL=5s
[4] Merchant does not attest. Waiting for TTL to expire (7s)…
[5] Calling claimRefund (anyone can call)
    ✓ agent: 100 USDC ← refunded
    ✓ vault: 0 USDC ← drained
    ✓ escrow state: refunded

Scenario 3 — Partial release (split)

Merchant signs a partial attestation (e.g. delivered 60%). On-chain split sends 60% to the merchant and refunds 40% to the agent — settled in a single transaction.

bun run examples/scenario-3-partial.ts
[4] partial_release(60) on-chain
    ✓ merchant: 0.6 USDC (expected 0.6)
    ✓ agent:    net debit 0.6 USDC
    ✓ escrow state: partiallyFulfilled, partial_pct=60

Scenario 4 — x402 HTTP paywall (E2E)

Run the demo merchant server in one terminal and the agent CLI in another. The merchant returns HTTP 402 with a challenge JSON; the agent creates an escrow and re-hits the endpoint with an X-Payment header; the server validates, runs the handler, and settles synchronously.

# Terminal 1
cd apps/demo-merchant
bun run start
# → http://localhost:8787

# Terminal 2
cd packages/sdk-ts
ANCHOR_PROVIDER_URL=https://api.devnet.solana.com \
ANCHOR_WALLET=~/.config/solana/id.json \
MERCHANT_URL=http://localhost:8787 \
TARGET_URL=https://news.ycombinator.com \
bun run examples/agent-cli.ts
✓ HTTP 200
  x-payment-settled: true
  x-aap-tx-sig:       <base58 signature>
  url scraped:  https://news.ycombinator.com
  scraped_at:   2026-04-26T01:59:53.807Z
✓ final escrow state: fulfilled

Demo merchant endpoints

  • GET /api/scrape?url=<url> — mock scrape result for an arbitrary URL.
  • GET /api/report — generated merchant risk report.
  • GET /api/inventory-check?sku=<sku> — inventory availability snapshot.
  • POST /api/book-hotel-mock — mock reservation receipt with overbooking covered by TTL refund.

Troubleshooting

AmountTooLow (6001)

The custody program rejects amounts below MIN_ESCROW_AMOUNT (1_000_000 stroops = 1 USDC). Pass at least 1 USDC, or redeploy the program with a smaller constant if you need micropayments.

AccountNotInitialized

The merchant doesn't have an ATA for the mint yet. Always run getOrCreateAssociatedTokenAccount(mint, merchant) during setup before the first release_escrow.

AttestationStale

The signed timestamp drifted > 5 minutes from on-chain clock. The SDK uses Date.now() by default — check the system clock.

Insufficient SOL

Each scenario creates a mint + 2 ATAs + escrow + vault (~0.012 SOL). Run solana airdrop 2 -u devnet.