From 4b1520c479ee1d38feed12efcca0a280b1ab9cdf Mon Sep 17 00:00:00 2001 From: franchukkk <223016348+enot3615@users.noreply.github.com> Date: Mon, 24 Aug 2026 15:27:21 -0700 Subject: [PATCH 1/4] =?UTF-8?q?docs(introduction):=20the=20dashboard=20exi?= =?UTF-8?q?sts=20=E2=80=94=20say=20so?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The introduction described the SDKs, the protocols and the payment flow, and never once mentioned dash.aifinpay.io. A reader arriving from the site's "Dashboard" link landed on a page with no word about the thing they had just clicked toward (founder, 2026-08-24). Adds a short section after "Pick your path": what the panel is for, and the one fact that is not obvious from either surface alone — code and panel edit the same registry, so `ensureResources()` shows up in the UI and anything drawn in the UI is picked up by the gate within about a minute. You can start in either. Links point at the two pages that already exist: /charge/dashboard and /charge/gateway. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01We1vVZLdj2vYtYaj7fjahX --- introduction.mdx | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/introduction.mdx b/introduction.mdx index 7f95b3a..a170638 100644 --- a/introduction.mdx +++ b/introduction.mdx @@ -89,6 +89,26 @@ both, independently. +## The dashboard + +Everything above can be driven from code alone, but the running product has a +control panel: **[dash.aifinpay.io](https://dash.aifinpay.io)**. + +It is where you register a site, price its endpoints, watch which agents paid +for what, set a payout wallet, and configure webhooks. Whatever you declare in +code with `ensureResources()` shows up there, and whatever you draw there is +picked up by the gate within about a minute — the two surfaces edit the same +registry, so you can start in either one. + + + + Endpoints, pricing tiers, payout wallet, and the paywall builder. + + + Point your domain at AiFinPay, or verify receipts in your own backend. + + + ## SDKs and tooling | Package | Install | Use it for | From 21df83052d40355bbd465b0ff0db55f558865049 Mon Sep 17 00:00:00 2001 From: franchukkk <223016348+enot3615@users.noreply.github.com> Date: Fri, 11 Sep 2026 13:00:38 -0700 Subject: [PATCH 2/4] docs: clarify receipt metering and repair onboarding links --- .github/workflows/check-links.yml | 16 +++++++++ AUDIT_2026-09-11.md | 40 ++++++++++++++++++++++ README.md | 42 ++++++++++++++--------- integration.mdx | 28 +++++++++++++--- introduction.mdx | 6 ++-- quickstart.mdx | 7 ++-- scripts/check-internal-links.mjs | 55 +++++++++++++++++++++++++++++++ 7 files changed, 166 insertions(+), 28 deletions(-) create mode 100644 .github/workflows/check-links.yml create mode 100644 AUDIT_2026-09-11.md create mode 100644 scripts/check-internal-links.mjs diff --git a/.github/workflows/check-links.yml b/.github/workflows/check-links.yml new file mode 100644 index 0000000..2d9982e --- /dev/null +++ b/.github/workflows/check-links.yml @@ -0,0 +1,16 @@ +name: Documentation links +on: + pull_request: + push: + branches: ['**'] +permissions: + contents: read +jobs: + links: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 22 + - run: node scripts/check-internal-links.mjs diff --git a/AUDIT_2026-09-11.md b/AUDIT_2026-09-11.md new file mode 100644 index 0000000..9fc776a --- /dev/null +++ b/AUDIT_2026-09-11.md @@ -0,0 +1,40 @@ +# Documentation audit — 2026-09-11 + +## Canonical source and deployment + +`aifinpay-docs` is the canonical docs source. It is a Mintlify site configured +by `docs.json`, with the intended custom domain `https://docs.aifinpay.io`. +The connected repository and custom-domain state require verification in the +Mintlify project; this checkout contains no provider-side deployment metadata +and has no local Docker deployment step. +`aifp-docs-work/` is a local archive/work folder and is not a Git checkout. + +## Verified findings + +- Main-site developer and docs navigation points to `https://docs.aifinpay.io`. +- The active provider entry point is `https://dash.aifinpay.io`; the + `charge/onboarding` page explicitly sends self-serve providers there. +- The legacy registry bridge flow is retained as an assisted path and does not + advertise `/partners/apply`, `/partners/onboard`, or `/partners/publish-api`. +- `quickstart.mdx` linked to the nonexistent `/mcp` and `/integrations` routes. + Those cards now point to the existing `/pay/mcp` and `/integration` pages, + with copy matching what those pages provide. +- The introduction no longer says settlement is live across 12 networks. It + now points to the readiness reference and describes Polygon as the current + SDK settlement path while per-chain routing rolls out. +- The integration guide now separates stateless receipt signature verification + from stateful quota accounting, documents the one-process limit of the + default `MemoryStore`, and requires a shared atomic store for multi-process + deployments. It also tells manual `/v1/pay` clients to follow any + `payment_authorization` requirement present in their quote. The development + receipt-authorization design was not presented as a production rollout. + +## Validation + +All relative links in the canonical MDX files were checked against the +repository page files, and every page listed by `docs.json` exists. The two +broken links above were the only missing targets found. No payment, API, +contract, or deployment behavior was changed. + +`scripts/check-internal-links.mjs` now provides the same dependency-free check +for local or CI use; it passes with 17 configured pages and no missing links. diff --git a/README.md b/README.md index 8c02cdd..9305f30 100644 --- a/README.md +++ b/README.md @@ -4,22 +4,24 @@ The AiFinPay developer documentation, built with [Mintlify](https://mintlify.com — the same platform our competitors use. Role × language structure: pay for services / charge for your API / reference. -## Go live at docs.aifinpay.io - -1. **Push to GitHub.** Put this folder in a repo (e.g. `AiFinPay/docs`). -2. **Connect Mintlify.** Sign up at https://mintlify.com → **Connect GitHub** → - pick the repo (and this subfolder if it isn't the repo root). Mintlify - rebuilds on every push and gives you a preview at `.mintlify.app`. -3. **Custom domain.** Mintlify dashboard → **Settings → Custom domain** → - `docs.aifinpay.io`. Mintlify shows a CNAME target. -4. **DNS (Cloudflare, `aifinpay.io` zone).** Add a CNAME: - `docs` → the value Mintlify gives (usually `cname.mintlify.app`), per - Mintlify's proxied/DNS-only instruction. -5. **Assets.** Drop logo files at `logo/light.svg` + `logo/dark.svg` and - `favicon.svg` (reuse the ones from `ofh-master/src/assets`). - -Then point the main-site nav **DOCS** link at `https://docs.aifinpay.io` -(currently it points at the interim React `/docs` hub). +## Source and deployment + +This repository is the canonical docs source. The `origin` remote is the +AiFinPay docs repository, whose default branch is `main`; a personal remote is +also configured for mirror or recovery workflows. Work on a branch, review it, +and merge or push through the normal repository workflow. + +The intended deployment mechanism is Mintlify at `https://docs.aifinpay.io`. +The connected repository and custom-domain status must be verified in the +Mintlify project; this checkout contains no provider-side deployment metadata. +Do not create a second application deployment or move the docs into another +repository. Mintlify should read `docs.json` and publish its configured page +tree. The main site already links its **DOCS** navigation to this domain, and +its **DASHBOARD** / provider CTAs go to the self-service customer panel at +[dash.aifinpay.io](https://dash.aifinpay.io). + +The logo and dark/light assets are already checked in under `logo/`; keep them +in place when editing the site. ## Local preview @@ -28,6 +30,14 @@ npm i -g mint mint dev # http://localhost:3000 ``` +## Local link check + +The repository includes a dependency-free check for local page links: + +```bash +node scripts/check-internal-links.mjs +``` + ## Structure ``` diff --git a/integration.mdx b/integration.mdx index 95d477c..e840582 100644 --- a/integration.mdx +++ b/integration.mdx @@ -37,7 +37,19 @@ Charging AI agents for your API takes three steps, and one decision. Either way the money path is identical and non-custodial: the agent pays on-chain **from its own wallet to yours** through the settlement contract, and -what your side checks is a signed receipt. Your server never holds funds. +what your side checks is a signed receipt. Signature verification is local and +stateless; quota consumption is stateful and needs a counter store. Your server +never holds funds. + + +The default `MemoryStore` is correct for one process only. If you run PM2, +Node cluster, multiple containers, or more than one pod, pass a shared atomic +store such as `redisStore` to `aifpGate`; otherwise each worker can spend the +same prepaid batch independently. Keep the default `onStoreError: "closed"` +behavior so a counter-store outage returns `503` instead of granting an +uncounted request. The receipt's Ed25519/JWKS signature check does not replace +this stateful metering step. + There is no sandbox yet: the first payment is real money on Polygon mainnet. @@ -60,7 +72,10 @@ The package has two halves with different credentials, on purpose: What the gate does per request: no receipt → answer `HTTP 402` with machine-readable payment instructions; valid receipt → verify the Ed25519 -signature locally, meter the prepaid quota down, let the request through. +signature locally, atomically meter the prepaid quota down in the configured +store, and let the request through. Signature verification needs only the +public JWKS; quota accounting still needs shared state when the gate runs in +more than one process. There is no call to AiFinPay on the hot path — our availability never becomes your latency. @@ -94,7 +109,7 @@ await merchant.ensureResources([ ]); const registry = new ResourceRegistry({ merchant }); -await registry.start(); // fail fast rather than serve with an empty registry +await registry.start(); // load the initial snapshot before serving const app = express(); app.use("/api", aifpGate({ merchantId: merchant.merchantId, registry })); @@ -167,13 +182,16 @@ HTTP 402 "how_to_pay": [ "POST https://api.aifinpay.io/v1/quote {…}", "settle the quoted batch on-chain from your own wallet", - "POST https://api.aifinpay.io/v1/pay {quote_id, chain, asset, tx_ref} -> quota receipt", + "POST https://api.aifinpay.io/v1/pay {quote_id, chain, asset, tx_ref, payment_authorization when the quote requires it} -> quota receipt", "retry this request with header: AIFP-Receipt: " ] } ``` -Agents on the AiFinPay SDK ([Node](/pay/node), [Python](/pay/python), +Keep the complete quote response. When it includes `payment_authorization`, the +client must sign the wallet-bound authorization described by that object and +send it with `/v1/pay`; do not invent or omit that field in a hand-written +client. Agents on the AiFinPay SDK ([Node](/pay/node), [Python](/pay/python), [MCP](/pay/mcp)) resolve that whole conversation from one `agent.pay(url)` call. diff --git a/introduction.mdx b/introduction.mdx index a170638..ab4d128 100644 --- a/introduction.mdx +++ b/introduction.mdx @@ -1,9 +1,9 @@ --- title: "AiFinPay — Payment Infrastructure for AI Agents" -description: "Stripe for autonomous AI agents. One line of code settles a real on-chain payment over HTTP, then returns the gated response. Non-custodial, multichain, token-free." +description: "Stripe for autonomous AI agents. One line of code settles a real on-chain payment over HTTP on currently enabled routes, then returns the gated response. Non-custodial, multichain, token-free." --- -**AiFinPay is payment infrastructure for autonomous AI agents.** One line of code — `agent.pay(url)` — and your agent settles a real on-chain payment — live across 12 networks — then receives the gated response. +**AiFinPay is payment infrastructure for autonomous AI agents.** One line of code — `agent.pay(url)` — and your agent settles a real on-chain payment on the route advertised by the challenge, then receives the gated response. Current payment-live routes and their evidence are tracked in the [network readiness reference](/reference/networks); the SDK's live settlement path is Polygon while per-chain routing is rolling out. It is the same idea Stripe brought to web checkouts, applied to machine-to-machine commerce: a drop-in rail an agent uses to pay for any API call, and a drop-in way for a provider to charge for one. @@ -12,7 +12,7 @@ It is the same idea Stripe brought to web checkouts, applied to machine-to-machi Agents hold their own keys and sign their own transactions. AiFinPay never takes custody of funds. - Contracts live on 12 mainnet networks — 7 with the full smart-contract stack. SDK settlement is live on Polygon today; per-chain routing is rolling out. + Network inventory and deployment status are tracked by readiness state. SDK settlement is live on Polygon today; per-chain routing is rolling out only as each route passes verification and paid end-to-end checks. No protocol token to buy, hold, or speculate on. Agents pay in MATIC/POL or SOL — the assets they already hold. diff --git a/quickstart.mdx b/quickstart.mdx index 0e707c3..caf5cdc 100644 --- a/quickstart.mdx +++ b/quickstart.mdx @@ -131,12 +131,11 @@ You saw one function call. Under the hood: Full `@aifinpay/agent` API for TypeScript and Node runtimes. - + Zero-code: drop `@aifinpay/mcp` into Claude Desktop, Cursor, or Windsurf and let the model pay for x402-gated APIs itself. - - Paste-and-run examples for LangChain, CrewAI, OpenAI Agents, AutoGPT, - and Flowise. + + Put a payment gate in front of your own API and verify receipts locally. diff --git a/scripts/check-internal-links.mjs b/scripts/check-internal-links.mjs new file mode 100644 index 0000000..c2d8a87 --- /dev/null +++ b/scripts/check-internal-links.mjs @@ -0,0 +1,55 @@ +#!/usr/bin/env node + +import fs from "node:fs"; +import path from "node:path"; +import process from "node:process"; + +const root = process.cwd(); +const configPath = path.join(root, "docs.json"); +const config = JSON.parse(fs.readFileSync(configPath, "utf8")); +const pages = new Set(); +const files = []; + +function walk(dir) { + for (const name of fs.readdirSync(dir)) { + if (name === ".git" || name === "node_modules") continue; + const file = path.join(dir, name); + const stat = fs.statSync(file); + if (stat.isDirectory()) walk(file); + else if (/\.(md|mdx)$/.test(name)) files.push(file); + } +} + +function configuredPages() { + for (const tab of config.navigation?.tabs ?? []) { + for (const group of tab.groups ?? []) { + for (const page of group.pages ?? []) pages.add(`/${page}`); + } + } +} + +walk(root); +configuredPages(); +const missingFiles = [...pages].filter( + (page) => !fs.existsSync(path.join(root, `${page.slice(1)}.mdx`)), +); +const missingLinks = []; +const linkPattern = /(?:\]\(|href=["'])(\/[A-Za-z0-9_./-]+)/g; + +for (const file of files) { + const source = fs.readFileSync(file, "utf8"); + for (const match of source.matchAll(linkPattern)) { + const target = match[1].replace(/[?#].*$/, ""); + if (!pages.has(target) && !fs.existsSync(path.join(root, `${target.slice(1)}.mdx`))) { + missingLinks.push(`${path.relative(root, file)} -> ${target}`); + } + } +} + +if (missingFiles.length || missingLinks.length) { + if (missingFiles.length) console.error("Missing configured pages:\n" + missingFiles.join("\n")); + if (missingLinks.length) console.error("Missing internal links:\n" + missingLinks.join("\n")); + process.exitCode = 1; +} else { + console.log(`OK: ${pages.size} configured pages and no missing internal links`); +} From 2b07742ba505e6614179ea6cc5aef613d6522b9d Mon Sep 17 00:00:00 2001 From: franchukkk <223016348+enot3615@users.noreply.github.com> Date: Fri, 11 Sep 2026 13:10:56 -0700 Subject: [PATCH 3/4] docs: repair favicon and use quote-defined payment terms --- AUDIT_2026-09-11.md | 16 ++++++++++++++++ docs.json | 2 +- favicon.ico | Bin 0 -> 22424 bytes quickstart.mdx | 10 ++++++---- scripts/check-internal-links.mjs | 6 +++++- 5 files changed, 28 insertions(+), 6 deletions(-) create mode 100644 favicon.ico diff --git a/AUDIT_2026-09-11.md b/AUDIT_2026-09-11.md index 9fc776a..bd87857 100644 --- a/AUDIT_2026-09-11.md +++ b/AUDIT_2026-09-11.md @@ -38,3 +38,19 @@ contract, or deployment behavior was changed. `scripts/check-internal-links.mjs` now provides the same dependency-free check for local or CI use; it passes with 17 configured pages and no missing links. + +The actual Mintlify local preview found a missing `/favicon.svg` referenced by +`docs.json`. The docs now reuse the main website's existing `favicon.ico`, and +the checker also verifies configured logo and favicon files. The Quickstart +render and corrected next-step links were checked in the local preview. The +Mintlify GitHub check skipped PR11 with "No eligible deployments found"; +this review does not claim that production docs have been updated. + +The Quickstart economics wording was also checked against the canonical pricing +reference and the current SDK settlement validators. The canonical AIFP-1 +route is gross-inclusive, but the Quickstart example targets a provider bridge +whose challenge defines the actual route; it now describes challenge-defined +terms and links to the canonical reference instead of hardcoding a split on a +generic bridge call. The example no longer prints `secret_b58`; it tells users +to keep a reusable secret in a local secret manager or keypair file and out of +shared logs. diff --git a/docs.json b/docs.json index 66fa3b7..29063c2 100644 --- a/docs.json +++ b/docs.json @@ -8,7 +8,7 @@ "light": "#83AED8", "dark": "#0A0E1A" }, - "favicon": "/favicon.svg", + "favicon": "/favicon.ico", "navigation": { "tabs": [ { diff --git a/favicon.ico b/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..142323c12f07b65b9c1a02031ee7fe9daedd474c GIT binary patch literal 22424 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

t+DCypUwz`btkbs7A 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 _lU!e&zyPZ!I#8eBf7+ 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 - The SDK submitted one transaction on Polygon mainnet — a gross-inclusive - AIFP-1 split (merchant 99% / AiFinPay 1% / creator 0%) in one verified tx. No - custodian touches the funds at any point. + The SDK submits one transaction using the settlement terms in the + challenge. It verifies the quoted amount and route economics before + signing; no custodian touches the funds at any point. For canonical AIFP-1 + economics, see [Pricing, units and limits](/reference/pricing-and-limits). The SDK retried your request with the payment proof headers, the diff --git a/scripts/check-internal-links.mjs b/scripts/check-internal-links.mjs index c2d8a87..d95746f 100644 --- a/scripts/check-internal-links.mjs +++ b/scripts/check-internal-links.mjs @@ -34,6 +34,9 @@ const missingFiles = [...pages].filter( (page) => !fs.existsSync(path.join(root, `${page.slice(1)}.mdx`)), ); const missingLinks = []; +const missingAssets = [config.favicon, config.logo?.light, config.logo?.dark] + .filter((asset) => typeof asset === "string" && asset.startsWith("/")) + .filter((asset) => !fs.existsSync(path.join(root, asset.slice(1)))); const linkPattern = /(?:\]\(|href=["'])(\/[A-Za-z0-9_./-]+)/g; for (const file of files) { @@ -46,9 +49,10 @@ for (const file of files) { } } -if (missingFiles.length || missingLinks.length) { +if (missingFiles.length || missingLinks.length || missingAssets.length) { if (missingFiles.length) console.error("Missing configured pages:\n" + missingFiles.join("\n")); if (missingLinks.length) console.error("Missing internal links:\n" + missingLinks.join("\n")); + if (missingAssets.length) console.error("Missing configured assets:\n" + missingAssets.join("\n")); process.exitCode = 1; } else { console.log(`OK: ${pages.size} configured pages and no missing internal links`); From f567eda3c8598969c649504a5407fea11e9f9ed6 Mon Sep 17 00:00:00 2001 From: franchukkk <223016348+enot3615@users.noreply.github.com> Date: Sat, 19 Sep 2026 10:12:43 -0700 Subject: [PATCH 4/4] docs: use public skills for owner and merchant onboarding --- README.md | 3 +- ai-discovery.mdx | 87 ++++++++++----- docs.json | 1 + introduction.mdx | 123 +++++++-------------- pay/manual-flow.mdx | 239 ++++++++-------------------------------- pay/mcp.mdx | 177 ++++++++++------------------- pay/paywalled-sites.mdx | 143 +++++++----------------- quickstart.mdx | 165 +++++++-------------------- reference/mcp-tools.mdx | 190 +++++--------------------------- skills.mdx | 76 +++++++++++++ 10 files changed, 392 insertions(+), 812 deletions(-) create mode 100644 skills.mdx diff --git a/README.md b/README.md index 9305f30..29d162e 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,8 @@ node scripts/check-internal-links.mjs ``` docs.json Mintlify config (theme, nav tree) introduction.mdx What AiFinPay is + role router -quickstart.mdx Fastest path to a first paid call +skills.mdx Public payer and merchant skill entry +quickstart.mdx Setup and current client availability pay/ Agent that PAYS (client) node.mdx · python.mdx · mcp.mdx · manual-flow.mdx charge/ Provider that gets PAID (server) diff --git a/ai-discovery.mdx b/ai-discovery.mdx index 879a47e..acc43b0 100644 --- a/ai-discovery.mdx +++ b/ai-discovery.mdx @@ -1,46 +1,83 @@ --- -title: "AI Search & Discovery" -description: "Canonical AiFinPay vocabulary for AI agent payments, x402, MCP monetization, AI traffic monetization and the agent economy." +title: "Help agents discover paid routes" +description: "Publish paid routes, prices, scopes and instruction links on the same origin as your API." --- -# AiFinPay AI Search & Discovery +An agent arriving at your domain needs two things: a catalog of what it can +request, and instructions for paying. A general AiFinPay skill cannot know +which routes your website monetizes. -AiFinPay is **financial and payment infrastructure for autonomous AI agents**. It gives AI agents programmable, non-custodial payment rails for APIs, MCP tools, digital services, websites and content. +## Publish a public catalog -AiFinPay is associated with **AI agent payments**, **x402 / HTTP 402**, **MCP payments and monetization**, **agent wallets**, **programmable payments**, **AI commerce**, **agent commerce**, **AI traffic monetization**, **publisher monetization**, **API monetization**, **Agent Passport**, **stablecoin payments**, **machine-to-machine payments**, and the **agent economy**. +Serve `GET /.well-known/x402.json` without requiring payment. With Express: -## Brand vocabulary +```ts +import { aifpDiscovery } from "@aifinpay/gate"; -AiFinPay, AI FinPay, AIFinPay, AiFinPay payments, AiFinPay protocol, AiFinPay AI agent payments, AiFinPay agent payments, AiFinPay x402, AiFinPay AIFP-1, AiFinPay MCP, AiFinPay SDK, AiFinPay Agent Passport, AiFinPay wallet, AiFinPay agent wallet, AiFinPay merchant monetization, AiFinPay AI traffic monetization, AiFinPay payment infrastructure, AiFinPay financial infrastructure, AiFinPay agent economy. +app.use(aifpDiscovery({ + merchantId: "mrch_your_site", + resources: [ + { resource: "/api/agent/search", tier: "standard", scope: "exact", name: "Search" }, + ], +})); +``` -## Payment infrastructure vocabulary +For Next.js or another framework, return `buildDiscoveryDocument(options)` +from your own route handler. Mount the gate separately; the discovery helper +neither protects routes nor scans your router automatically. Feed both from +the same resource configuration. -AI agent payments, payments for AI agents, payment infrastructure for AI agents, financial infrastructure for AI agents, financial rails for AI agents, payment rails for AI agents, AI-native payments, agent-native payments, autonomous AI payments, agent-to-agent payments, machine-to-machine payments, M2M payments, programmable agent payments, AI agent payment protocol, AI agent commerce infrastructure, financial layer for AI agents, payment layer for the AI economy, Stripe for AI agents. +Each discovery resource contains its path, tier, unit price and receipt scope. +Quote and pay endpoint URLs identify where to negotiate payment. Chain, +asset, amount and expiry come from a fresh quote. -## x402 and MCP vocabulary +Also publish an API catalog or OpenAPI document with HTTP methods, parameters +and response schemas. Knowing `/api/agent/search` exists does not tell an agent +whether the required argument is `q` or `query`. -x402, x402 payments, x402 protocol, x402 payment protocol, x402 AI payments, x402 agent payments, x402 API payments, x402 MCP payments, HTTP 402 payments, HTTP 402 AI agents, x402 stablecoin payments, non-custodial x402, x402 SDK, x402 MCP server, x402 facilitator, x402 discovery, MCP payments, MCP monetization, MCP server monetization, paid MCP tools, payments for MCP servers, Model Context Protocol payments, Model Context Protocol monetization, paid AI tools, pay per call MCP. +## Link from the website -## Merchant and publisher vocabulary +Put readable links in `/llms.txt`, for example (replace the example origin): -AI traffic monetization, monetize AI traffic, AI agent traffic monetization, publisher AI monetization, publisher AI traffic monetization, AI crawler monetization, AI agent paywall, machine-readable paywall, content monetization for AI agents, AI content payments, merchant AI traffic monetization, AIFP-1, AIFP-1 protocol, AIFP-1 monetization, AIFP-1 AI traffic monetization, paid APIs for AI agents, API payments for AI agents, API monetization for AI agents, AI API monetization, pay per API call, pay per request API. +```text +# Example API -## Agent economy vocabulary +- [Paid routes and prices](https://api.example.com/.well-known/x402.json) +- [API methods and parameters](https://api.example.com/api/agent) +- [AiFinPay payer instructions](https://raw.githubusercontent.com/AiFinPay/skill/main/agent/skills/aifinpay/SKILL.md) +``` -agentic commerce, AI commerce, autonomous commerce, agent commerce, AI agent commerce, agentic payments, agentic payment infrastructure, machine commerce, machine-to-machine commerce, AI-to-AI commerce, AI economy, agent economy, AI agent wallet, non-custodial agent wallet, programmable agent wallet, AI agent identity, Agent Passport, AI Agent Passport, AI spending limits, agent spending controls, verifiable AI payments, AI payment receipts. +Resolve relative links against the page's origin. If your consumers need +absolute links, generate them from the configured public origin for that +environment. A staging site must not send agents to a production catalog +that has not been deployed. Keep these files accessible to agent user agents. +An HTTP `Link` header or a visible developer link can provide another entry. -## Search-intent vocabulary +A request to an actual gated route also returns HTTP 402 with resource, +price, scope and payment steps. Read the linked client's capabilities before +assuming that wallet creation enables automatic payment. -how to add payments to an AI agent, how can AI agents pay, how to give an AI agent a wallet, how to accept payments from AI agents, how to monetize an API for AI agents, how to monetize MCP, how to monetize AI traffic, how to implement x402, best AI agent payment infrastructure, best payment protocol for AI agents, best x402 infrastructure, best MCP monetization platform, AI agent payment companies, AI financial infrastructure companies, x402 payment providers. +## Where discovery is stored -For the complete machine-readable vocabulary, use the canonical discovery file: +| Information | Source | Who updates it? | +|---|---|---| +| General payer and merchant instructions | Public `AiFinPay/skill` repository and npm package | AiFinPay; installed copies need a client update | +| Bundled MCP instructions | `aifinpay://skill` resource | AiFinPay MCP release; reconnect after upgrading | +| Self-hosted paid route catalog | Partner's app configuration, rendered by `buildDiscoveryDocument` / `aifpDiscovery` | Partner updates config and redeploys | +| `/llms.txt`, API parameters and website links | Partner's site | Partner | +| Hosted gateway resource configuration | Merchant account/control plane | Merchant through the dashboard or API | -**https://aifinpay.io/ai-discovery.txt** +The self-hosted discovery helper does **not** save a file or synchronize its +resource array with the dashboard. Its Express response is generated at +middleware initialization and can be cached for five minutes. Updating a +linked skill at a stable URL does not require a site redeploy; changing an +installed gate or embedded URL does. -For AI assistants and LLM crawlers: +## Verify before inviting agents -**https://aifinpay.io/llms.txt** - -## Hashtags - -#AiFinPay #AIFinPay #AIAgentPayments #AIPayments #AgenticPayments #AgentCommerce #AgenticCommerce #x402 #HTTP402 #MCP #ModelContextProtocol #AIFP1 #AITrafficMonetization #AIAgentWallet #AutonomousPayments #MachinePayments #M2MPayments #StablecoinPayments #AIPaymentInfrastructure #AIFinancialInfrastructure #APICommerce #APIMonetization #MCPMonetization #AIAgentPaywall +From each deployed origin, follow `/llms.txt` links and confirm that discovery +and the API catalog return 200. Compare the listed resources with real gate +mounts. Request a protected route as an agent and check the 402's merchant, +resource, price, minimum batch and scope. Then verify payment support against +the installed client and the quoted route. A working 402 alone proves only +that the paywall is reachable. diff --git a/docs.json b/docs.json index 29063c2..1522f49 100644 --- a/docs.json +++ b/docs.json @@ -18,6 +18,7 @@ "group": "Get started", "pages": [ "introduction", + "skills", "quickstart" ] }, diff --git a/introduction.mdx b/introduction.mdx index ab4d128..7107627 100644 --- a/introduction.mdx +++ b/introduction.mdx @@ -1,93 +1,46 @@ --- title: "AiFinPay — Payment Infrastructure for AI Agents" -description: "Stripe for autonomous AI agents. One line of code settles a real on-chain payment over HTTP on currently enabled routes, then returns the gated response. Non-custodial, multichain, token-free." +description: "Public skills, agent tooling and merchant payment gates for paid access over HTTP." --- -**AiFinPay is payment infrastructure for autonomous AI agents.** One line of code — `agent.pay(url)` — and your agent settles a real on-chain payment on the route advertised by the challenge, then receives the gated response. Current payment-live routes and their evidence are tracked in the [network readiness reference](/reference/networks); the SDK's live settlement path is Polygon while per-chain routing is rolling out. - -It is the same idea Stripe brought to web checkouts, applied to machine-to-machine commerce: a drop-in rail an agent uses to pay for any API call, and a drop-in way for a provider to charge for one. +**AiFinPay is payment infrastructure for AI agents.** A merchant can publish +paid resources through an HTTP 402 gate. An agent discovers the terms and, +when its client supports the offered settlement route, buys access and reuses +a scoped payment receipt. - - Agents hold their own keys and sign their own transactions. AiFinPay never takes custody of funds. - - - Network inventory and deployment status are tracked by readiness state. SDK settlement is live on Polygon today; per-chain routing is rolling out only as each route passes verification and paid end-to-end checks. - - - No protocol token to buy, hold, or speculate on. Agents pay in MATIC/POL or SOL — the assets they already hold. + + Install the payer skill, connect your tools and inspect a site's paid routes. - - Payment rides on top of the standard x402 challenge. Sign once, retry the request, get your data. + + Use the merchant skill to integrate the gate and publish your API catalog. - - There is no AiFinPay token, and no internal credit either. mSECCO was retired on 2026-08-06: crediting it required an extra chain call on every payment, and it was never minted — total supply is zero. - - -## What is x402? - -[x402](https://www.x402.org) revives the long-reserved HTTP `402 Payment Required` status code as a real protocol. Instead of returning data, a protected endpoint answers an unauthenticated request with `402` plus a small manifest describing how to pay. The client settles the payment, attaches proof, and retries — and this time receives `200` with the payload. - -AiFinPay implements x402 end-to-end. The agent SDK auto-detects the facilitator flavor (AiFinPay native, Coinbase x402, and others), signs an Ed25519 challenge, settles on-chain, retries the request, and returns the response — all behind a single `agent.pay(url)` call. +## Start with the skill ```bash -# Python -pip install aifinpay-agent - -# Node / TypeScript -npm install @aifinpay/agent - -# MCP server (Claude Desktop, Cursor, Windsurf, Continue) -npx @aifinpay/mcp +npx skills add AiFinPay/skill ``` -## How a payment flows +Choose `aifinpay` for the paying side or `aifinpay-merchant` for the merchant +side. Skills provide instructions; MCP and SDK packages provide tools. +Read [the skill setup guide](/skills) and [quickstart](/quickstart). - - - The agent calls a protected URL. The server answers `402` with a manifest and a one-time `nonce`. - - - The agent signs `SHA256("AiFinPay-x402:{nonce}:{pubkey}")` with its Ed25519 key and settles the on-chain payment. - - - The agent retries the request with three auth headers. The server verifies and returns `200` plus the payload. - - - -## Two protocols, one platform - -Which side of the transaction you are on decides which protocol — and which -host and headers — you use. Mixing them up is the single most common source of -confusion, so it is worth thirty seconds now. - -| | Paying for services | Charging for your API | -|---|---|---| -| Protocol | AiFinPay X402 (AIFP-2) | AIFP-1 | -| You are | an agent spending money | a merchant earning it | -| Host | `bridge.aifinpay.io/{provider}/…` | `gateway.aifinpay.io/{your-slug}/…` | -| Headers | `x-agent-pubkey`, `x-nonce`, `x-signature`, `x-tx-hash` | `AIFP-Agent-Id`, `AIFP-Receipt` | -| Start at | [Pay for services](/pay/node) | [Charge for your API](/charge/gateway) | - -Both settle on-chain straight to a wallet, and neither ever holds your funds. If -you are doing both — paying for some APIs while charging for your own — you use -both, independently. + +The published MCP 2.1.0 exposes wallet, history, quota and non-signing +preparation tools. It does not execute payments. Node SDK AIFP-1 payments also +require a compatible reviewed deployment; see [current payment support](/pay/paywalled-sites). +A live merchant gate is not evidence that every published client supports it. + -## Pick your path +## How the gate works - - - Your agent needs to call paid APIs. Install the SDK and use `agent.pay(url)` to settle any x402-protected endpoint. - - - You run an API and want agents to pay for it. Accept AiFinPay with a single HTTP call inside your existing service — no wallet, no chain library, no KYC. - - - Networks, live contract addresses, headers, and field names — the canonical lookup for integrators. - - +The agent discovers paid routes on the merchant's own origin, requests a +resource, and receives HTTP 402 with payment terms. A supported executor +settles an approved batch from the agent's wallet. After verification, the +agent receives a receipt and retries with `AIFP-Receipt` to get the data. +Further covered calls spend quota from that receipt. See [the flow](/pay/manual-flow). ## The dashboard @@ -95,10 +48,9 @@ Everything above can be driven from code alone, but the running product has a control panel: **[dash.aifinpay.io](https://dash.aifinpay.io)**. It is where you register a site, price its endpoints, watch which agents paid -for what, set a payout wallet, and configure webhooks. Whatever you declare in -code with `ensureResources()` shows up there, and whatever you draw there is -picked up by the gate within about a minute — the two surfaces edit the same -registry, so you can start in either one. +for what, set a payout wallet, and configure webhooks. Resource registration through `ensureResources()` and the dashboard uses +the same registry. A self-hosted discovery array is separate: publish and +update it in the partner app, as described in [discovery](/ai-discovery). @@ -111,12 +63,13 @@ registry, so you can start in either one. ## SDKs and tooling -| Package | Install | Use it for | -|---|---|---| -| `aifinpay-agent` (Python) | `pip install aifinpay-agent` | `agent.pay(url)` in Python agents | -| `@aifinpay/agent` (Node / TypeScript) | `npm install @aifinpay/agent` | `agent.pay(url)` in JS/TS agents | -| `@aifinpay/mcp` (MCP server) | `npx @aifinpay/mcp` | Give an LLM payment tools in Claude Desktop, Cursor, Windsurf, Continue | +| Package | Purpose | +|---|---| +| `@aifinpay/skill` | Payer and merchant instructions for assistants | +| `@aifinpay/mcp` | Wallet, history, quota and non-signing preparation tools | +| `@aifinpay/agent` | Node/TypeScript SDK; settlement depends on supported deployment | +| `aifinpay-agent` | Python SDK; consult the installed version's supported routes | +| `@aifinpay/gate` | Merchant-side receipt verification and quota metering | - - Using an MCP client? Drop the `@aifinpay/mcp` server into your config and the model gains payment tools like `payable_fetch(url)`, `agent_address`, `agent_quote`, `pay_with_split`, and `quote_split` — letting it autonomously settle any x402-gated API. - +[Publish discovery](/ai-discovery) so agents can learn your site's routes, +prices and parameters without guessing. diff --git a/pay/manual-flow.mdx b/pay/manual-flow.mdx index bf05e9c..736fb3a 100644 --- a/pay/manual-flow.mdx +++ b/pay/manual-flow.mdx @@ -1,196 +1,49 @@ --- -title: "x402 by hand" -description: "Implement the AiFinPay x402 payment flow without the SDK — the raw 402 challenge, the on-chain split payment, and the Ed25519 identity gate, step by step." +title: "AIFP-1 payment flow" +description: "Understand discovery, quotes, settlement verification and prepaid receipts without guessing transaction calldata." --- -You don't need our SDK to pay through AiFinPay. The protocol is plain HTTP plus one on-chain transaction. This page implements the full flow by hand — for minimal-runtime agents, unsupported languages, or anyone who wants to see exactly what the SDK does. - -AiFinPay is token-free: there is no protocol coin to acquire or hold. You pay in assets you already have (native POL / SOL or USDC / USDT), and settlement happens directly on-chain. - - -There are **two flows**, and both start with an HTTP `402`: - -- **Paid call** — buy a service per request, settling on-chain. Most common. -- **Identity gate** — prove who you are with an Ed25519 signature to reach gated endpoints (live stats, protocol docs). - - - -In production, use the SDK (`agent.pay(url)` / `agent.call({provider})`) — it handles the 402 parsing, chain selection, signing and retries shown below for you. This page is the raw protocol underneath it. - - -## Flow 1 — Paid call (pay per request, settle on-chain) - -Buy a service per request. You call the resource, get a `402` with everything needed to pay, settle once on-chain through the `B2BSplitter`, then resend the same request with proof. - - - - Send your normal request. The bridge answers `402 Payment Required` with the payment challenge. - - ```http - POST https://bridge.aifinpay.io// - content-type: application/json - - { "...": "your request body" } - ``` - - - - The `pay_matic` block (Polygon) tells you the splitter, the exact amounts, the `function_signature` to call, and a one-time `order_id`. A `pay_solana` block is included when the provider has a Solana merchant configured. - - ```json - { - "error": "Payment Required", - "protocol": "AIFP-1 (contracts v5.3)", - "facilitator": "aifinpay-pay-matic", - "pay_matic": { - "chain": "polygon", - "splitter": "0xE34Fc0E6694821c600Fa0955C0F74720ea6d8440", - "merchant_wallet": "0x…", - "total_wei": "15000000000000000", - "merchant_amount_wei": "…", - "treasury_amount_wei": "…", - "ip_creator_amount_wei": "…", - "order_id": "venice-abc123", - "function_signature": "payMatic(address,address,string)", - "ttl_seconds": 600 - }, - "retry": { - "legacy_pay_matic": { "method": "POST", "headers": ["x-tx-hash", "x-order-id"], "same_body": true } - } - } - ``` - - - The same `402` also carries a standard x402 `accepts` array (ERC-3009 USDC / USDT via a facilitator) for clients that speak it. The native-POL `pay_matic` path below is the simplest to implement by hand. - - - - In the `protocol` field, **AIFP-1** is the payment protocol version and **v5.3** is the revision of the AiFinPayCore contract on Polygon — two independent version lines. SDKs should key behavior off `AIFP-1`, never off the contract revision. - - - - - Send `total_wei` to the `splitter`. It splits the payment to the provider, the treasury and the IP creator atomically in one transaction. Pass the challenge's `merchant_wallet` and `order_id` verbatim, and an `ipCreator` address — use the value from the challenge if present, never the zero address. - - ```ts - import { createWalletClient, http } from "viem"; - import { polygon } from "viem/chains"; - - const abi = [{ - type: "function", name: "payMatic", stateMutability: "payable", - inputs: [ - { type: "address", name: "merchant" }, - { type: "address", name: "ipCreator" }, - { type: "string", name: "orderId" }, - ], - outputs: [], - }]; - - const hash = await wallet.writeContract({ - address: pm.splitter, - abi, - functionName: "payMatic", - args: [pm.merchant_wallet, ipCreator, pm.order_id], - value: BigInt(pm.total_wei), - chain: polygon, - }); - - await publicClient.waitForTransactionReceipt({ hash }); - ``` - - - - Repeat the **same** request with two headers. The bridge re-reads the on-chain `Payment` event (merchant, amount, `orderId`), confirms it matches the issued order, then forwards the upstream response. - - ```http - POST https://bridge.aifinpay.io// - x-tx-hash: 0x… # the payMatic tx hash - x-order-id: venice-abc123 - content-type: application/json - - { "...": "the same request body" } - ``` - - On success you get `200`, the provider's result, and an `x-payment-receipt` header. Each `order_id` is single-use and the on-chain transaction is the source of truth, so a network-level retry just resends the same two headers — you never pay twice. - - - **Solana variant.** When the `402` carries a `pay_solana` block, submit its `b2b_pay_with_split` instruction (`program_id`, `merchant_wallet`, `treasury`, the lamport amounts, `order_id`), then resend with `x-solana-tx` + `x-order-id` instead of `x-tx-hash` + `x-order-id`. - - - - -## Flow 2 — Identity gate (prove who you are, Ed25519) - -Some endpoints (live stats, protocol docs) gate on agent **identity** rather than a per-call payment. You sign a one-time nonce with your Ed25519 key, and your pubkey must own a Seat PDA on Solana. - - - - Call the gated endpoint without identity headers. The `402` returns a fresh `x-nonce` (60-second TTL), `x-nonce-expires`, plus the manifesto path, treasury, mint addresses, the agreement hash, and the mSECCO threshold. mSECCO are non-transferable usage credits, not a tradable asset. - - ```json - { - "error": "Payment Required", - "protocol": "AIFP-1 (contracts v5.3)", - "manifesto": "/manifesto.json", - "treasury_vault": "AnbjcK3uD5KYFtb3EuUxHTyJMfC4oyLo7hF2uELfKagN", - "min_usd": 1, - "min_msecco": 100, // vestigial — mSECCO was retired 2026-08-06; ignore it - "idl_uri": "/idl.json", - "usdc_mint": "…", - "usdt_mint": "…", - "usdc_ata_treasury": "…", - "usdt_ata_treasury": "…", - "agreement_hash": "…", - "x-nonce": "…", - "x-nonce-expires": "2026-06-26T00:01:00.000Z" - } - ``` - - - - Call `reserve_seat_sol` (SOL, priced via the Pyth oracle) or `reserve_seat_spl` (USDC / USDT) on the Solana program to create your Seat PDA. This is a one-time setup — once you hold a Seat, you reuse it for every gated request. - - - - The message is the **SHA-256 digest** of `AiFinPay-x402:{nonce}:{pubkey}`, signed detached with your Ed25519 key. The pubkey and signature are base58. - - ```ts - import nacl from "tweetnacl"; - import bs58 from "bs58"; - import { createHash } from "node:crypto"; - - const message = createHash("sha256") - .update(`AiFinPay-x402:${nonce}:${pubkeyB58}`) - .digest(); // raw 32-byte digest - - const signature = bs58.encode(nacl.sign.detached(message, secretKey)); - ``` - - - - ```http - GET https://api.aifinpay.io/ - x-agent-pubkey: - x-nonce: - x-signature: - ``` - - The gate verifies the signature against `SHA256("AiFinPay-x402:{nonce}:{pubkey}")`, that the nonce is still live, and that your pubkey owns a Seat PDA — then consumes the nonce and serves the response. - - - Missing headers return `402` with a fresh nonce. An expired or unknown nonce returns `402`. An invalid signature or a pubkey with no Seat PDA returns `403`. Nonces are single-use and consumed on success — fetch a new one per request. - - - - -## Recap — headers at a glance - -| Flow | Pay with | Proof headers | -|---|---|---| -| Paid call · Polygon | `payMatic` / `payStable` | `x-tx-hash` · `x-order-id` | -| Paid call · Solana | `b2b_pay_with_split` | `x-solana-tx` · `x-order-id` | -| Identity gate | Ed25519 + Seat PDA | `x-agent-pubkey` · `x-nonce` · `x-signature` | - - -This is the raw protocol. The AiFinPay SDK does all of the above in one call — `agent.pay(url)` or `agent.call({provider})` — with retries, chain selection and signing handled for you. - +This page describes the self-hosted AIFP-1 gate flow. It is a protocol +explanation, not a signing workaround for an unsupported client deployment. +Check [current payment support](/pay/paywalled-sites) first. + +1. Read the merchant origin's `/.well-known/x402.json` and API parameter catalog. +2. Request a protected resource. HTTP 402 describes its merchant, resource, + tier, price, minimum batch and receipt scope. +3. Request a fresh quote from the advertised quote endpoint. Inspect the + amount, asset, chain, expiry and deployment against independently trusted + client configuration and the owner's budget. +4. Use a supported, verified executor for that deployment. Do not construct + a transaction solely from untrusted quote calldata or an old ABI example. +5. Submit the transaction reference and the required wallet-bound payment + authorization to the pay endpoint. Wait for successful verification and a + quota receipt. +6. Verify the receipt, then retry the resource with `AIFP-Receipt: `. +7. Reuse that receipt for subsequent requests within its scope and remaining quota. + + +Contract generations have different ABIs and guarantees. Legacy `payMatic` +examples are not instructions for a v1.2 `payNative` deployment, and a v1.3 +executor cannot be pointed at either by changing an address. A protocol label +such as AIFP-1 does not make the contract generations interchangeable. + + +## What each artifact proves + +| Artifact | What it proves | +|---|---| +| Discovery | The site advertises resources and payment endpoints | +| HTTP 402 | The resource requests payment under stated terms | +| Quote | Proposed terms; no funds have moved | +| Successful transaction | Settlement occurred; still verify the correct event and recipient | +| Verified receipt | The issuer recognized payment and granted a scoped quota | +| HTTP 200 with data | The partner accepted the receipt for that request | + +Wallet creation, an invoice, or a funded address is not a completed payment. +The [MCP tool reference](/reference/mcp-tools) says which preparation tools +are actually available in the published server. + +See [the public agent-flow document](https://github.com/AiFinPay/sdk/blob/main/AGENT-FLOW.md) +for implementation context and the installed package's versioned documentation +for supported executors. Keep transaction recovery state private; never put +raw signing material or bearer receipts in logs or recordings. diff --git a/pay/mcp.mdx b/pay/mcp.mdx index 5d2c28d..be64f5e 100644 --- a/pay/mcp.mdx +++ b/pay/mcp.mdx @@ -1,146 +1,89 @@ --- -title: "Use AiFinPay from Claude (MCP)" -description: "Install the @aifinpay/mcp server so Claude can pay for AI services autonomously over x402 — no payment code required." +title: "Connect the AiFinPay MCP server" +description: "Set up persistent agent identity, payment history, quotas and non-signing payment preparation." --- -`@aifinpay/mcp` is an [MCP](https://modelcontextprotocol.io) server that exposes AiFinPay's autonomous x402 payment loop as agent-callable tools. Drop it into Claude Desktop (or any MCP-aware runtime) and your agent can buy services on its own — detect an `HTTP 402`, sign, pay, and retry — without you writing a line of payment code. +`@aifinpay/mcp` connects AiFinPay tools to an MCP-compatible assistant. Install +[the payer skill](/skills) first so the assistant knows the workflow. - -AiFinPay is payment infrastructure for AI agents — the Stripe for autonomous agents. It is **token-free**: there is nothing to buy, hold, or trade to use it. Agents pay real stablecoins per call. mSECCO are non-transferable usage credits, not a tradable asset. - + +Verified against published version **2.1.0** on September 19, 2026: this MCP +server does not register payment-signing tools. `payable_fetch`, `agent_call` +and `agent_quote` are unavailable. A quote or invoice does not move funds. + -## Install +## Initialize a persistent wallet ```bash -# Globally — usable as `npx @aifinpay/mcp` from any client config -npm install -g @aifinpay/mcp +npx @aifinpay/mcp init ``` -## Configure Claude Desktop +`init` selects an existing configured identity or creates a local keystore. +The default file is `~/.aifinpay/agent.json`. Existing wallets are retained. +Set `AIFINPAY_WALLET_PASSPHRASE` through your local secret environment before +creation if you want the MCP keystore encrypted. The MCP process needs the +same passphrase to read it. Without that variable, this init command creates +a plaintext file protected by filesystem permissions. + +On a first plaintext wallet creation in an interactive terminal, init also +prints a one-time recovery key. Prepare encryption before recording init; +never capture or share that recovery output. + +Do not share seed backups, keystore contents or passphrases. The client can +work with public addresses; secrets should stay outside chat and recordings. +Do not fund an ephemeral identity. + +## Connect your client -Add the server to `~/Library/Application Support/Claude/claude_desktop_config.json`: +Add this server through your client's MCP settings: ```json { "mcpServers": { "aifinpay": { "command": "npx", - "args": ["@aifinpay/mcp"], - "env": { - "AIFINPAY_AGENT_SECRET": "", - "AIFINPAY_MAX_USD": "0.50" - } + "args": ["-y", "@aifinpay/mcp@2.1.0"] } } } ``` -Restart Claude Desktop. Claude can now call any of the tools below — `payable_fetch`, `agent_call`, `pay_with_split`, and the read-only marketplace directory — like any other tool. +For a custom wallet directory, configure `AIFINPAY_HOME` as its absolute path. +Configure an encrypted wallet's passphrase privately in the host environment. +Some desktop clients do not inherit terminal environment variables. - -Always set `AIFINPAY_MAX_USD`. It is a hard cap on any single payment and is your primary safety control when an autonomous agent is spending on its own. - - -## First run — generating an agent - -If `AIFINPAY_AGENT_SECRET` is not set, the server generates an **ephemeral** keypair and prints it to stderr at startup: - -``` -[warn] no AIFINPAY_AGENT_SECRET set — generated EPHEMERAL agent. - address: 9HucVaL5yinJ4MfBKCFnz5QJBGwK33bfSQKw15pSe3Ch - secret: 2vfeWAYfkpTNGSgDpBonzmjkckrTKa5GTnhhztY141YcSKYrqCvtojVukQAQiJbbRLgdcfEdyqHbRMsUft6Pb7nD - >> Save this secret to AIFINPAY_AGENT_SECRET to keep the agent across restarts. -``` +Connect or restart the server, then ask for `agent_address`. Compare it with +the address printed by init. If init ran while the server was connected, +`agent_reload` reloads wallet files in that connection. Changes to environment +variables or package versions require reconnecting the process. -Save the printed secret to `AIFINPAY_AGENT_SECRET` in your client config so the agent identity — and any funded Seat — persists across restarts. +## Try the supported tools - -Treat `AIFINPAY_AGENT_SECRET` like a private key. Never commit it or paste it into chats. Anyone with it controls the agent and its funds. - +> Show my persistent agent address and my indexed transaction history. Then +> inspect the settlement routes and tell me which are enabled. Do not send a +> payment. -## Environment variables +`agent_history` can inspect indexed Polygon transactions or receipt history; +`agent_quota` reads quota reported by the AiFinPay meter. A self-hosted +merchant meters locally, so this counter is not its authoritative remaining +balance. Coverage is explicit in the response: +these are not a full wallet explorer. See [all registered tools](/reference/mcp-tools). -| Var | Default | Purpose | -|---|---|---| -| `AIFINPAY_AGENT_SECRET` | — | Base58 secret. If absent → ephemeral agent printed to stderr. | -| `AIFINPAY_BASE_URL` | `https://aifinpay.io` | Backend URL for nonce + funding probes. | -| `AIFINPAY_TIMEOUT_MS` | `30000` | Request timeout. | -| `AIFINPAY_MAX_USD` | — | Hard cap per single payment. Strongly recommended. | +The bundled instructions are exposed as the MCP resource `aifinpay://skill`. +Your client must read the resource to use them; connecting the server does not +mean every host automatically loads every resource. -## Tools +## Configuration -The server exposes 16 tools: 7 for payment and agent identity, and 9 read-only marketplace directory tools. - -### Payment / agent - -| Tool | What it does | -|---|---| -| `payable_fetch(url, opts?)` | Fetch any URL. On `HTTP 402`, auto-detect the facilitator, sign, pay, and retry. | -| `agent_call({provider, body})` | Pay a registered AiFinPay provider and return its response (unified call). | -| `agent_quote(url)` | Inspect a 402 challenge without paying — quoted amount + facilitator flavor. | -| `agent_address()` | Return the agent's address so you know where to fund it. | -| `agent_claim_self(...)` | Publish/claim this agent on the public AiFinPay network directory. | -| `pay_with_split(...)` | Retired compatibility tool; returns `legacy_split_route_retired` and moves no funds. | -| `quote_split(...)` | Retired compatibility tool; use a canonical AIFP-1 quote. | - -### Marketplace directory (read-only) - -| Tool | What it does | +| Variable | Purpose | |---|---| -| `list_providers()` | List the AI services available through AiFinPay with per-call prices. | -| `provider_info(name)` | Details for one provider (price, networks, service type). | -| `provider_status()` | Which provider bridges are currently reachable. | -| `service_coverage()` | Which categories AiFinPay covers and the providers in each. | -| `network_stats()` | Public protocol statistics. | -| `leaderboard()` | Public on-chain leaderboard of AiFinPay agents. | -| `quote_cost(...)` | Preview canonical gross-inclusive AIFP-1 economics (no payment). | -| `verify_passport(pubkey)` | Whether a key holds an AiFinPay AgentPassport. | -| `agent_profile(address)` | Public profile + activity summary for an agent. | - -## Try it in Claude - -Once the server is running, drive it in natural language. Claude picks the right tools: - - - - Ask Claude for `agent_address()`, then send stablecoins to that address so it has a balance to spend. - - - "What AI services can I pay for through AiFinPay?" → Claude calls `list_providers()` and `provider_info(name)`. - - - "How much would this 402 endpoint cost?" → Claude calls `agent_quote(url)` or `quote_cost(...)` — no payment is made. - - - "Fetch this paid endpoint and summarize it" → Claude calls `payable_fetch(url)`, which pays and retries automatically, staying under `AIFINPAY_MAX_USD`. - - - -## How `payable_fetch` works - -1. Sends the request unauthenticated. -2. On `402`, the underlying `@aifinpay/agent` SDK detects the facilitator flavor (AiFinPay native, Coinbase x402, …). -3. Signs a payment payload and retries. -4. Returns `{ status, ok, headers, body }` to the agent. - -The flow is identical to calling `agent.pay(url)` directly — this package just wraps it as an MCP tool surface so LLM agents can call it without writing payment code. - -## Programmatic use - -You can also embed the server in your own MCP host: - -```ts -import { createServer, loadConfigFromEnv } from "@aifinpay/mcp"; -import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; - -const { server } = await createServer({ - ...loadConfigFromEnv(), - agentSecretB58: "your-secret-here", - maxAmountUsd: 0.10, -}); -await server.connect(new StdioServerTransport()); -``` - - -Works with Claude Desktop, MCP Inspector, and any MCP-aware agent runtime. The server communicates over stdio. - +| `AIFINPAY_HOME` | Directory containing the local `agent.json` keystore | +| `AIFINPAY_WALLET_PASSPHRASE` | Decrypt an encrypted keystore; keep private | +| `AIFINPAY_AGENTS_FILE` / `AIFINPAY_AGENT_ID` | Select a project identity by absolute file path and ID | +| `AIFINPAY_BASE_URL` | AiFinPay backend origin | +| `AIFINPAY_MAX_USD` | Underlying per-call budget setting; does not enable signing | +| `AIFINPAY_MODE=dev` | Expose dev quoting with a separate dev backend | + +Wallet selection is: `SEED_HASH`, project agents file, legacy +`AIFINPAY_AGENT_SECRET`, then the local keystore. Invalid or ambiguous +configured identities fail instead of silently creating a different wallet. diff --git a/pay/paywalled-sites.mdx b/pay/paywalled-sites.mdx index 7d37ab5..a5ec7cb 100644 --- a/pay/paywalled-sites.mdx +++ b/pay/paywalled-sites.mdx @@ -1,121 +1,58 @@ --- title: "Paying a paywalled site" -description: "Crawl a site or API behind an AiFinPay gateway: one on-chain prepayment buys a batch, and every call after that costs a header." +description: "Discover the route, check client compatibility, and understand prepaid batches and receipt scope." --- -Some sites and APIs put their content behind an AiFinPay gateway rather than -implementing a payment protocol themselves. An agent meeting one gets an HTTP -**402** with `"protocol": "AIFP-1"`. +A site integrated with `@aifinpay/gate` returns HTTP **402** with +`protocol: "AIFP-1"`. One on-chain settlement buys a batch of billing units; +subsequent covered requests use an `AIFP-Receipt` header and consume quota. -The important thing about this shape: **you do not pay per request.** One -on-chain settlement buys a prepaid batch of billing units, and every call the -batch covers costs a header and nothing else. Paying per request would cost more -in gas than the content. +## Check the client before paying -## One call +As verified on September 19, 2026: -```ts -import { AiFinPayAgent } from "@aifinpay/agent"; +- `@aifinpay/mcp@2.1.0` has no payment-signing tool. +- `@aifinpay/agent@2.0.3` has an AIFP-1 `fetchPaid` path that requires an + independently reviewed Polygon v1.3 deployment pin and matching quote + format. It does not execute a legacy v1.2 quote. +- `agent.pay` and AIFP-1 `fetchPaid` are different protocol paths; one is not + a fallback for a rejected deployment in the other. -const agent = await AiFinPayAgent.fromSeed(process.env.AGENT_SEED!); +If the merchant offers an incompatible route, stop before signing. Installing +[the skill](/skills) provides instructions, not a different executor. Consult +the installed package's documentation for its exact configuration requirements. -// Handles the 402: quotes, settles on-chain, gets a receipt, retries. -const res = await agent.fetchPaid("https://gateway.aifinpay.io/acme/articles/2026/x"); -const article = await res!.text(); -``` +## Discover the resource -Every later call the same batch covers sends the receipt and settles nothing: +Read `/.well-known/x402.json` on the **same origin** as the target site. Use +its paths, prices and scopes, then read the site's API catalog for required +parameters. Request the chosen route and inspect the 402 minimum batch. +A fresh quote supplies chain, asset, amount, merchant and expiry. -```ts -await agent.fetchPaid("https://gateway.aifinpay.io/acme/articles/2026/y"); // no transaction -await agent.fetchPaid("https://gateway.aifinpay.io/acme/articles/2026/z"); // no transaction -``` +For example, `dev.ratersapp.com` publishes both discovery and `/api/agent`. +Its `/api/agent/genres` was priced at $0.0005 per standard request with an +exact scope and a $0.10 minimum batch on the verification date. Its quoted +v1.2 route was incompatible with the public client above; this is an +integration readiness check, not a working payment quickstart. -`fetchPaid` returns `null` when your own budget caps refuse the payment — see -[Budget caps](/pay/node#budget-caps). Anything that is not an AIFP-1 402 comes -back untouched, so you can point it at any URL. +## Receipt scope -## Scope: the difference between usable and ruinous - -A receipt covers a **scope**, and the default is the path prefix rather than the -exact URL. This matters more than anything else on this page. - - -With `scope: "exact"` a batch pays for one URL. On a content site, where an -agent reads each page once, that means one settlement and one batch minimum per -page — the effective price of an article becomes the batch minimum no matter -what the site charges, and a 670,000-URL site cannot be crawled for a sensible -amount of money. - - -| Scope | Covers | Use for | -|---|---|---| -| `prefix` *(default)* | the path and everything under it — `/articles/` covers `/articles/2026/x`, and **not** `/articles-internal` | crawling a section | -| `merchant` | every path on that merchant's gateway | one agent, one site, many sections | -| `exact` | one path | an endpoint you call repeatedly | - -```ts -// Buy one batch for the whole site. -await agent.fetchPaid(url, {}, { scope: "merchant" }); - -// Or a specific section. -await agent.fetchPaid(url, {}, { scope: "prefix", resource: "/articles/" }); -``` - -Widening the scope changes **where** units may be spent, never how many a call -costs: the gateway charges the weight of the route you actually hit, from the -merchant's own registry. A premium route takes ten units out of a batch bought -against a standard one. - -A receipt is a bearer token. A merchant-wide one is your whole prepaid balance -in a single JWT, which is why `prefix` is the default rather than `merchant`. - -## What it costs - -| | | +| Scope | Covers | |---|---| -| Standard action | **$0.0005** | -| Complex action | **$0.002** | -| Premium action | **$0.005** | -| Minimum batch | **$0.10** — 200 standard actions | -| Gas per settlement | ~$0.003, amortised across the batch | - -Omit `units` and the client buys about ten cents' worth, computed from the price -the gateway states in its own 402 — so the batch stays the same amount of money -if the tiers move. Set it explicitly to buy a bigger one: - -```ts -await agent.fetchPaid(url, {}, { units: 20_000 }); // ~$10 at $0.0005/unit -``` - -The batch drains as you spend it; when it runs out the next call settles a new -one automatically. `agent.aifp1Receipts` lists what you are currently holding. - -## Concurrency - -Workers sharing one agent are safe. Purchases are coalesced per site: if ten -workers hit a 402 at the same moment, one buys a batch and the rest wait for it -and spend the same one, rather than settling ten times. - -## What this does not do - - -**Polygon only.** `/v1/pay` verifies settlement on Polygon and nowhere else, so a -quote that does not accept `polygon` is refused rather than settled somewhere the -receipt could never be issued. +| `exact` | The quoted resource path | +| `prefix` | The quoted path and covered descendants | +| `merchant` | Resources covered by that merchant-wide receipt | -**Native POL settlement.** The deployed splitter has no ERC-20 entrypoint, so a -quote is settled in POL even when it lists stablecoins as acceptable. +Read the scope offered by the merchant. Do not assume that buying one endpoint +opens the whole site or that a client can widen a scope unilaterally. -**Known gateways only.** The client refuses to settle against a host that is not -a recognised AiFinPay gateway. A 402 is the answer to a request that carried no -credentials, so it is unauthenticated by construction — paying whoever answers is -how an agent gets drained by a page that simply claims to be a paywall. Pass -`gatewayOrigins` for a self-hosted gateway, and never for a host whose paywall -you do not control. - +## Verify the result -## Charging for your own content +A complete supported flow is: quote → approved on-chain settlement → verified +receipt → HTTP 200 data → another covered request using the same receipt. +The second request must consume quota without creating another transaction. +Match the payment transaction with the merchant dashboard's record. -The other side of this page is [Charge for your API](/charge/gateway) — a -merchant points their traffic at a gateway URL and writes no payment code at all. +Network gas is separate from the batch price and varies. Keep receipts private: +they are bearer credentials for prepaid access. On a timeout after broadcast, +recover the existing transaction and receipt before considering any new payment. diff --git a/quickstart.mdx b/quickstart.mdx index fe4886b..72fc556 100644 --- a/quickstart.mdx +++ b/quickstart.mdx @@ -1,143 +1,54 @@ --- title: "Quickstart" -description: "From a clean machine to your first paid API call in under a minute." +description: "Choose an agent or merchant workflow, install the public skill and verify the available tools." --- -AiFinPay is payment infrastructure for AI agents — Stripe for autonomous -agents. One line of code, `agent.pay(url)`, settles a real on-chain -payment and returns the gated response. No API key, no KYC, no -custodian. The protocol is token-free: there is nothing to buy, list, or -hold to use it. +Start with the [AiFinPay skill](/skills). It contains separate instructions +for an agent owner buying access and a merchant charging for a site or API. - - You'll need a few cents of MATIC on Polygon to fund your agent's - wallet. The SDK generates the wallet for you — you just send funds to - the address it prints. - +```bash +npx skills add AiFinPay/skill +``` - - - Pick your language. Both packages are published as stable `1.0.0`. +## Agent owners - - ```bash Python - pip install aifinpay-agent - ``` +For an assistant with MCP support, connect `@aifinpay/mcp` using the +[MCP setup guide](/pay/mcp). For your own application, install the Node or +Python SDK and follow its versioned package documentation. - ```bash Node - npm install @aifinpay/agent - ``` - - +```bash +# MCP wallet setup +npx @aifinpay/mcp init - - `Agent.new()` generates a fresh keypair and prints the funding - address. Persist the secret (`secret_b58` / `secretB58`) if you want - to reuse this agent identity later. +# Node application +npm install @aifinpay/agent - - ```python Python - from aifinpay import Agent +# Python application +pip install aifinpay-agent +``` - agent = Agent.new() - print("Fund this address with a few cents of MATIC:", agent.address) - # If reusing this identity, store agent.secret_b58 in a local secret - # manager or keypair file; never print it into shared logs. - ``` - - ```ts Node - import { Agent } from "@aifinpay/agent"; - - const agent = Agent.new(); - console.log("Fund this address with a few cents of MATIC:", agent.address); - ``` - - - - - Send a small amount of MATIC to the address printed above — a few - cents is plenty for the example call. Funds stay in your agent's own - wallet until a payment settles; AiFinPay never holds them. - - - - `agent.pay(url)` handles the full HTTP 402 handshake for you: it - reads the payment challenge, signs it, settles on-chain, retries the - request with the proof headers, and returns the gated response. - - - ```python Python - resp = agent.pay( - "https://bridge.aifinpay.io/io-net/chat/completions", - body={"model": "meta-llama/Llama-3.3-70B-Instruct", - "messages": [{"role": "user", "content": "Hello"}]}, - ) - print(resp.json()["choices"][0]["message"]["content"]) - print("tx hash:", resp.headers.get("x-payment-receipt")) - ``` - - ```ts Node - const res = await agent.pay( - "https://bridge.aifinpay.io/io-net/chat/completions", - { body: { model: "meta-llama/Llama-3.3-70B-Instruct", - messages: [{ role: "user", content: "Hello" }] } }, - ); - const data = await res.json(); - console.log(data.choices[0].message.content); - ``` - - - - - You get back the upstream response body — in this case a model - completion. The `x-payment-receipt` header carries the on-chain - transaction hash, so every paid call is independently verifiable on - Polygonscan. - - - -## What just happened - -You saw one function call. Under the hood: - - - - The server returned **HTTP 402** with a JSON block listing the - chain, asset, `payTo` address, amount, and a one-time `nonce`. - - - The SDK submits one transaction using the settlement terms in the - challenge. It verifies the quoted amount and route economics before - signing; no custodian touches the funds at any point. For canonical AIFP-1 - economics, see [Pricing, units and limits](/reference/pricing-and-limits). - - - The SDK retried your request with the payment proof headers, the - server verified on-chain, forwarded to the upstream service, and - returned the response. - - +Choose the runtime you use; installing MCP already includes its SDK dependency. +Keep the persistent wallet local and verify its public address in the client. - There is no token to acquire to use AiFinPay, and no internal credit to earn. - mSECCO was retired on 2026-08-06: crediting it required an extra chain call on every payment, and it was never minted — total supply is zero. Agents pay in real assets and nothing else changes hands. +As checked on September 19, 2026, MCP 2.1.0 does not expose payment-signing +tools. Node 2.0.3 AIFP-1 `fetchPaid` requires a reviewed Polygon v1.3 deployment +pin and compatible quotes. A site offering an older v1.2 route cannot be made +compatible by installing the skill or funding a wallet. Do not bypass a route +verification failure. See [payment support](/pay/paywalled-sites). -## Next steps +Ask the agent to inspect the target origin's `/.well-known/x402.json` and its +API catalog. Agree on the resource, receipt scope, batch cost and separate gas +budget before a supported payment is executed. Read [discovery](/ai-discovery) +for the difference between general instructions and site-specific routes. + +## Merchants + +Open [the dashboard](https://dash.aifinpay.io), register your site and follow +[the merchant onboarding guide](/charge/onboarding). Use the +`aifinpay-merchant` skill to guide integration of `@aifinpay/gate`. - - - Full `aifinpay-agent` API: agent persistence, custom payloads, and - canonical gross-inclusive settlement and fail-closed route verification. - - - Full `@aifinpay/agent` API for TypeScript and Node runtimes. - - - Zero-code: drop `@aifinpay/mcp` into Claude Desktop, Cursor, or - Windsurf and let the model pay for x402-gated APIs itself. - - - Put a payment gate in front of your own API and verify receipts locally. - - +Publish discovery on the same origin as your protected routes. After a real +payment, verify the merchant, amount and transaction in the dashboard; a +quote or HTTP 402 response is not a completed payment. diff --git a/reference/mcp-tools.mdx b/reference/mcp-tools.mdx index 3a2ebca..7988f0a 100644 --- a/reference/mcp-tools.mdx +++ b/reference/mcp-tools.mdx @@ -1,171 +1,39 @@ --- -title: "MCP Tools Reference" -description: "The 7 tools exposed by @aifinpay/mcp — the agent payment + identity surface. (A read-only directory toolset is on the roadmap.)" +title: "MCP tools reference" +description: "The actual registered tools in @aifinpay/mcp 2.1.0." --- -`@aifinpay/mcp` is an [MCP](https://modelcontextprotocol.io) server that wraps -AiFinPay's autonomous x402 payment loop as agent-callable tools. Drop it into -Claude Desktop, MCP Inspector, or any MCP-aware runtime and your agent can pay -for services and browse the AiFinPay network without you writing any payment -code. +Verified against published **@aifinpay/mcp 2.1.0** on September 19, 2026. +Use the server's `tools/list` for exact input schemas in your installed version. -It exposes **7 tools** that move money or bind identity. AiFinPay is payment -infrastructure for AI agents — settlement happens in SOL, USDC, USDT, or POL, -and there is no token to buy. The internal credit that used to be earned was retired on 2026-08-06 and never minted, so there is no -tradable asset. +| Tool | Purpose | +|---|---| +| `agent_address` | Read the selected wallet's public addresses | +| `agent_reload` | Reload configured wallet files in the current connection | +| `agent_quota` | Inspect hosted-meter quota; self-hosted consumption is tracked by the merchant | +| `agent_history` | Read indexed transactions or retained batch history | +| `agent_passport_resolve` | Resolve a public Agent Passport | +| `settlement_routes` | Inspect route availability | +| `settlement_invoice` | Prepare a non-signing settlement invoice | +| `settlement_solana` | Inspect Solana settlement instructions | +| `settlement_casper` | Inspect Casper settlement instructions | +| `deployment_info` | Read deployment metadata | +| `dev_payment_quote` | Request a dev quote; only registered in dev mode | - -The 7 tools below need a funded agent — see [agent setup](#agent-setup) below. -A read-only directory toolset (`list_providers`, `network_stats`, -`leaderboard`, …) is on the roadmap and **not yet registered** in the published -server — see [Roadmap](#roadmap-directory-tools). Until then, use the -public REST discovery endpoints (`/api/leaderboard`, `/.well-known/x402.json`) for catalog/stats. - +There are ten default tools, plus the optional dev quote tool. None signs or +broadcasts a payment. `agent_reload` changes the in-process wallet selection; +it does not transfer funds. -## Payment tools +The server also exposes the Markdown resource `aifinpay://skill`. Read it for +wallet selection and the current workflow. -These tools can settle on-chain or bind the agent to an account. Always set a -hard spend cap with `AIFINPAY_MAX_USD` before enabling them. +## Tools absent from this release -| Tool | Signature | What it does | -|---|---|---| -| `payable_fetch` | `(url, method?, body?, headers?, …)` | Fetch any URL. On HTTP 402, auto-detect the facilitator, sign, pay, and retry. Returns `{ status, ok, headers, body }`. | -| `agent_call` | `({ provider, body, method?, … })` | Pay a registered AiFinPay provider (e.g. `exa`, `io-net`, `venice`) and return its response. | -| `agent_quote` | `(url, method?)` | Inspect a 402 challenge **without** paying — detected facilitator flavor plus quoted amount and fee preview. | -| `agent_address` | `()` | Return the agent's Solana (base58) and Polygon (EVM) addresses so you know where to fund it. | -| `agent_claim_self` | `({ magic_link_url, label? })` | Attach this agent to a user's AiFinPay account by signing a claim challenge with its own key. | -| `pay_with_split` | `(legacy fields accepted)` | Retired compatibility tool. Returns `legacy_split_route_retired`; never creates an invoice or moves funds. | -| `quote_split` | `(legacy fields accepted)` | Retired compatibility tool. Use a canonical AIFP-1 quote. | +`payable_fetch`, `agent_call`, `agent_quote`, `pay_with_split`, `quote_split` +and `agent_claim_self` are not registered. Do not instruct an agent to call +them or to replace a missing payment tool with improvised transaction signing. - -`pay_with_split` returns on-chain instructions/invoice; it does **not** itself -broadcast funds. The agent executes the returned instructions with its own -chain SDK. `chain` accepts `"solana"` or `"polygon"`, and `merchant_amount` is -a string in base units (lamports for Solana, wei for Polygon). - +## Start here -## Roadmap: directory tools - - -These read-only directory tools are **planned but not yet registered** in the -published `@aifinpay/mcp` server — calling them will fail with "unknown tool". -They are documented here as the intended surface. For catalog/stats today, use -the public REST discovery endpoints (`/api/leaderboard`, `/.well-known/x402.json`). This section is -generated from the roadmap, not from the live `tools/list`. - - -When shipped, these will never move funds, never require auth, and return the -public AiFinPay network catalog and statistics. - -| Tool | Signature | What it does | -|---|---|---| -| `list_providers` | `()` | List the AI services available through AiFinPay (web search, image generation, LLM inference, …) with per-call price and supported networks. | -| `provider_info` | `({ name })` | Details for one provider by name — price, supported networks, service type, homepage. | -| `provider_status` | `()` | Report which provider bridges are currently reachable (up/down). | -| `service_coverage` | `()` | Which categories of AI service AiFinPay covers and the providers in each. | -| `network_stats` | `()` | Public protocol statistics: supported networks, active agents, total settled volume, active providers. | -| `leaderboard` | `()` | The public on-chain leaderboard of AiFinPay agents ranked by settled volume. | -| `quote_cost` | `({ amount, asset? })` | Preview gross-inclusive AIFP-1 economics (99/1/0) without paying. | -| `verify_passport` | `({ pubkey })` | Whether an agent public key holds an AiFinPay AgentPassport, plus its on-chain status. | -| `agent_profile` | `({ address })` | Public profile and activity summary for an agent by its EVM or Solana address. | - -## Install - -```bash -# Install globally so it's usable as `npx @aifinpay/mcp` from any client config -npm install -g @aifinpay/mcp -``` - -## Use with Claude Desktop - -Add the server to `~/Library/Application Support/Claude/claude_desktop_config.json`, -then restart Claude Desktop: - -```json -{ - "mcpServers": { - "aifinpay": { - "command": "npx", - "args": ["@aifinpay/mcp"], - "env": { - "AIFINPAY_AGENT_SECRET": "", - "AIFINPAY_MAX_USD": "0.50" - } - } - } -} -``` - -Claude can now call any of the 7 tools above like any other tool. - -## Agent setup - -If `AIFINPAY_AGENT_SECRET` is not set, the server generates an **ephemeral** -keypair and prints it to stderr at startup: - -```text -[warn] no AIFINPAY_AGENT_SECRET set — generated EPHEMERAL agent. - address: 9HucVaL5yinJ4MfBKCFnz5QJBGwK33bfSQKw15pSe3Ch - secret: 2vfeWAYfkpTNGSgDpBonzmjkckrTKa5GTnhhztY141YcSKYrqCvtojVukQAQiJbbRLgdcfEdyqHbRMsUft6Pb7nD - >> Save this secret to AIFINPAY_AGENT_SECRET to keep the agent across restarts. -``` - -Save the printed secret to `AIFINPAY_AGENT_SECRET` so the agent identity (and -any funded Seat) persists across restarts. Call `agent_address` to find out -where to send funds. - - -The secret controls the agent's funds. Store it like any other private key — -never commit it, and keep `AIFINPAY_MAX_USD` set as a hard per-payment cap. - - -## Environment variables - -| Var | Default | Purpose | -|---|---|---| -| `AIFINPAY_AGENT_SECRET` | — | Base58 secret. If absent, an ephemeral agent is generated and printed to stderr. | -| `AIFINPAY_BASE_URL` | `https://aifinpay.io` | Backend URL for nonce and funding probes. | -| `AIFINPAY_TIMEOUT_MS` | `30000` | Request timeout in milliseconds. | -| `AIFINPAY_MAX_USD` | — | Hard cap per single payment. Strongly recommended. | - -## Programmatic use - -```ts -import { createServer, loadConfigFromEnv } from "@aifinpay/mcp"; -import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; - -const { server } = await createServer({ - ...loadConfigFromEnv(), - agentSecretB58: "your-secret-here", - maxAmountUsd: 0.10, -}); -await server.connect(new StdioServerTransport()); -``` - -## How `payable_fetch` works - - - - The tool sends the request with no payment header. - - - On `402`, the underlying [`@aifinpay/agent`](../node) SDK detects the - facilitator flavor (AiFinPay native, Coinbase x402, …). - - - It signs a payment payload and retries the request. - - - Returns `{ status, ok, headers, body }` to the agent. - - - -The flow is identical to calling `agent.pay(url)` directly — this package just -wraps it as an MCP tool surface so LLM agents can pay without writing payment -code. - - -Use `payable_fetch` (not the host's generic web-fetch tool) for any URL that -might be a paid endpoint — a plain fetch can only see the 402 challenge and -cannot sign the x402 payment header to settle it. - +[Install the skill](/skills), [connect MCP](/pay/mcp), or read +[site-specific route discovery](/ai-discovery). diff --git a/skills.mdx b/skills.mdx new file mode 100644 index 0000000..bbeb3c2 --- /dev/null +++ b/skills.mdx @@ -0,0 +1,76 @@ +--- +title: "Start with an agent skill" +description: "The public entry point for agent owners and merchants: install the right AiFinPay instructions, then connect the tools." +--- + +An AiFinPay skill teaches your assistant how to use the product. Choose the +paying side if you own an agent, or the merchant side if you own a site or API. +The skills are published in [@aifinpay/skill](https://www.npmjs.com/package/@aifinpay/skill) +and the [AiFinPay/skill repository](https://github.com/AiFinPay/skill). + +## Install in your assistant + +```bash +npx skills add AiFinPay/skill +``` + +Select `aifinpay` for an agent buying access, or `aifinpay-merchant` for a +merchant integrating payments. The installer lets you choose the agent client. +Installing `@aifinpay/skill` with npm downloads the files; it does not by itself +register the skill with your assistant. + +If your client accepts a Markdown instruction URL, use: + +- [Payer instructions](https://raw.githubusercontent.com/AiFinPay/skill/main/agent/skills/aifinpay/SKILL.md) +- [Merchant instructions](https://raw.githubusercontent.com/AiFinPay/skill/main/agent/skills/aifinpay-merchant/SKILL.md) + + +A skill is instructions, not a payment executor. As checked on September 19, +2026, `@aifinpay/mcp@2.1.0` exposes wallet, history, quota and non-signing +preparation tools. It does not expose `payable_fetch` or `agent_call`. +Installing the skill does not change that. See the [MCP tool reference](/reference/mcp-tools). + + +## I own an agent + +1. Install the `aifinpay` skill. +2. Connect [the MCP server](/pay/mcp), or use the SDK from your own agent code. +3. Create or select a persistent wallet with `npx @aifinpay/mcp init`. +4. Ask the agent to inspect the target site's discovery document and API catalog. +5. Agree on the resource, scope, batch price and separate gas budget. Confirm + that the installed executor supports the quoted deployment before funding + or requesting a payment. + +A useful first prompt: + +> Use the AiFinPay skill to inspect this website's paid API. Read discovery +> on the same origin, list suitable routes and their parameters, and explain +> the batch price and receipt scope. Check whether your installed tools can +> execute the offered route before proposing a payment. + +For example, on `dev.ratersapp.com`, read +[`/.well-known/x402.json`](https://dev.ratersapp.com/.well-known/x402.json) and +[`/api/agent`](https://dev.ratersapp.com/api/agent). The first lists paid routes; +the second describes their request parameters. Use the dev origin throughout. +A published catalog alone does not mean the installed client can settle it. + +## I own a website or API + +Use `aifinpay-merchant`, register the site in the +[dashboard](https://dash.aifinpay.io), and integrate `@aifinpay/gate` following +[the self-hosted integration guide](/integration). + +Publish the paid route catalog and link it from the site. See +[agent discovery](/ai-discovery) for ownership, storage and deployment details. + +## Where the instructions live + +The public skills live in `AiFinPay/skill`, under +`agent/skills/aifinpay/SKILL.md` and `agent/skills/aifinpay-merchant/SKILL.md`. +The skill installer saves a copy for the selected client. Update that copy +when upgrading; it is not a live subscription to the source file. + +The MCP server also exposes a bundled skill as the resource +`aifinpay://skill`. That copy belongs to the installed MCP version. +A website's paid routes live in its own discovery document, separately from +these general AiFinPay instructions.