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/3] =?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/3] 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/3] 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`);