Automatic micro-donations powered by x402. Drop-in Express/Next.js middleware that sends USDC to charities on every user action. npm install x402charity.
x402charity is an early-stage TypeScript project in the AI payments / x402 ecosystem, focused on base, blockchain, charity, coinbase. It currently has 2 GitHub stars and 17 forks, and sits alongside related tools like tdm-sdk, piprail, gold-402, Sentinel, RequestTap-Router, provider.
Open-source micro-donation server powered by the x402 protocol on Solana. Deploy your own server, then trigger SPL USDC donations with a single HTTP call from any product.
Live Demo | Deploy to Vercel | npm install | Fork this repo
Built and maintained by AllScale Lab.
Project status (Solana port): This repo was recently ported from Base/EVM to Solana. The implementation builds cleanly and follows Coinbase's
@x402/svmreference, but the end-to-end flow has not yet been exercised against the live x402 facilitator on devnet or mainnet from this codebase. The first deploy should run onsolana-devnetagainst the Circle faucet. See Known Issues & Future Work for the punch list. The Live Demo and thex402charitynpm package may still be serving the previous EVM version until a new release is cut.
x402 Charity lets any company add micro-donations to their product. Every user action — a trade, an API call, a game action — can trigger a small USDC donation to a charity of your choice.
┌──────────┐ ┌──────────────────┐ ┌──────────────────────┐
│ User │ │ Your Product │ │ x402 Charity Server │
│ Action │─────>│ Server │─────>│ (this repo) │
└──────────┘ └──────────────────┘ └──────────┬───────────┘
e.g. swap, calls POST /donate │
API call, with amount │ signs partial
game move │ SPL transfer tx
v
┌──────────────────┐
│ x402 Facilitator │
│ (run by Coinbase)│
└────────┬─────────┘
│ co-signs as
│ fee payer +
│ submits to Solana
v
┌──────────────────┐
│ Charity Wallet │
│ receives USDC │
└──────────────────┘
Step by step:
POST /donate with an amount (e.g. $0.001) to your deployed x402 charity serverThe user never needs a wallet, never signs anything, and never even knows a donation happened. Your company funds all donations from a single pre-funded USDC wallet — no SOL required.
Create a new Solana wallet (Phantom, Solflare, or solana-keygen new -o id.json) and export the secret key. Two formats are accepted:
[12,34,...,255] — 64 numbers4xZ... — a single base58-encoded 64-byte stringFund it with USDC on Solana. SOL is not required — the x402 facilitator pays gas.
Option A: Run locally
git clone https://github.com/allscale-io/x402charity.git
cd x402charity
cp .env.example .env # edit .env with your keys
pnpm install
pnpm dev
Option B: Docker
git clone https://github.com/allscale-io/x402charity.git
cd x402charity
docker build -t x402charity .
docker run -p 3402:3402 \
-e DONATION_PRIVATE_KEY="[12,34,...]" \
-e CHARITY_WALLET="So11111111..." \
-e CHARITY_NAME="Give Directly" \
-e DONATION_NETWORK="solana-mainnet" \
-e DONATE_API_KEY="$(openssl rand -hex 32)" \
x402charity
Your server is live at http://localhost:3402 with a built-in dashboard.
From your product server — any language, any framework:
const res = await fetch('https://your-charity-server.com/donate', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer YOUR_DONATE_API_KEY',
},
body: JSON.stringify({ amount: '$0.001' }),
});
const receipt = await res.json();
console.log(receipt.txHash); // on-chain Solana signature
| Variable | Required | Description | Default |
|---|---|---|---|
DONATION_PRIVATE_KEY |
Yes | Solana donor secret key. Base58 64-byte secret or JSON array of 64 bytes. | — |
CHARITY_WALLET |
Yes | Solana wallet address (base58 pubkey) of the charity. | — |
CHARITY_NAME |
No | Display name for the charity | My Charity |
CHARITY_DESCRIPTION |
No | Description of the charity | — |
DONATION_NETWORK |
No | solana-mainnet or solana-devnet. Mainnet requires FACILITATOR_URL to be set — the default x402.org facilitator currently advertises Solana devnet only. |
solana-devnet |
FACILITATOR_URL |
No | Override the x402 facilitator URL. Required for solana-mainnet. PayAI (https://facilitator.payai.network) is the current mainnet-capable option; self-hosted facilitators also work. |
https://x402.org/facilitator |
BASE_URL |
No | Public URL of your server (auto-detected on Vercel) | http://localhost:3402 |
PORT |
No | Server port | 3402 |
DONATE_API_KEY |
No | Secret key to protect POST /donate. If set, callers must send Authorization: Bearer <key>. If unset, the endpoint is open. Set this in production. |
— (open) |
CORS_ORIGINS |
No | Comma-separated list of allowed CORS origins (e.g. https://myapp.com,https://admin.myapp.com). If unset, all origins are allowed. |
* (all origins) |
Security notes:
- Never commit your
DONATION_PRIVATE_KEYto version control. Use environment variables or a secret manager (e.g. Vercel Environment Variables, AWS Secrets Manager). The private key controls the donation wallet funds.- Set
DONATE_API_KEYin production. Without it, anyone who knows your server URL can trigger donations and drain your wallet. Generate one with:openssl rand -hex 32
| Method | Path | Description |
|---|---|---|
POST |
/donate |
Trigger a donation. Requires Authorization: Bearer <DONATE_API_KEY> if API key is set. Optional body: { "amount": "$0.001" } |
GET |
/donations |
JSON list of recent donations with totals. Accepts ?limit=N (default 50, max 200). |
GET |
/charity |
Charity info (name, wallet, chain) + USDC/SOL balances |
GET |
/address |
Donation wallet address + USDC/SOL balances |
GET |
/health |
Health check |
npm install x402charity
The simplest way — just call your deployed server's POST /donate endpoint:
await fetch('https://your-charity-server.com/donate', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer YOUR_DONATE_API_KEY',
},
body: JSON.stringify({ amount: '$0.001' }),
});
import { x402charity } from 'x402charity/express';
app.use('/api', await x402charity({
privateKey: process.env.DONATION_PRIVATE_KEY,
donateEndpoint: 'https://your-charity-server.com/donate',
charity: {
id: 'my-charity',
name: 'My Charity',
walletAddress: 'So11111111...',
chain: 'solana-devnet',
description: 'My charity description',
verified: false,
x402Endpoint: 'https://your-charity-server.com/donate',
},
amount: '$0.001',
shouldDonate: (req) => req.method === 'POST',
}));
Note: the middleware factory is async (Solana keypair import requires an
await).
// middleware.ts
import { x402charity } from 'x402charity/next';
export default await x402charity({
privateKey: process.env.DONATION_PRIVATE_KEY,
donateEndpoint: 'https://your-charity-server.com/donate',
charity: {
id: 'my-charity',
name: 'My Charity',
walletAddress: 'So11111111...',
chain: 'solana-devnet',
description: 'My charity description',
verified: false,
x402Endpoint: 'https://your-charity-server.com/donate',
},
amount: '$0.001',
matcher: '/api/*',
});
# Configure once (writes to ~/.x402charity/config.json, chmod 600):
npx x402charity config set-key '[12,34,...]' # base58 secret or JSON-array
npx x402charity config set-network solana-devnet
# Or pass via env vars:
export X402_PRIVATE_KEY='[12,34,...]'
export X402_NETWORK=solana-devnet
# Browse charities and donate:
npx x402charity list
npx x402charity donate testing-charity '$0.001' --network solana-devnet
npx x402charity config show
Or deploy manually:
DONATION_PRIVATE_KEY — Solana donor secret key (base58 or JSON array)CHARITY_WALLET — Solana wallet address (base58 pubkey)CHARITY_NAME — display name for the charity (optional)DONATION_NETWORK — solana-mainnet or solana-devnet (default: solana-devnet)DONATE_API_KEY — secret key to protect POST /donate (recommended). Generate with: openssl rand -hex 32Note:
BASE_URLis auto-detected on Vercel. If you deploy elsewhere (Railway, Fly, etc.), setBASE_URLto your server's public URL (e.g.https://your-app.fly.dev).
Before donations can work, your donation wallet needs USDC on the correct network:
solana-devnet (testnet, the default): Get devnet USDC from the Circle faucet (choose Solana → Devnet). No SOL needed for the donor wallet.solana-mainnet: Fund the donor wallet with real USDC on Solana, and point FACILITATOR_URL at a mainnet-capable facilitator (e.g. https://facilitator.payai.network). No SOL needed in this wallet — the facilitator pays gas. The default https://x402.org/facilitator does not currently support Solana mainnet.ATA bootstrapping: SPL USDC is held in an Associated Token Account (ATA) derived from
(wallet, mint). The x402 facilitator is expected to include an ATA-create instruction on the first donation to a charity whose ATA does not yet exist, but this has not been verified end-to-end from this codebase yet — see Known Issues. If your first mainnet donation fails because the charity ATA doesn't exist, pre-create it manually withspl-token create-account <USDC_MINT> --owner <CHARITY_WALLET>(rent is ~0.002 SOL, one-time).
This repo is the source of truth for three published artefacts:
| Artefact | Where | What's published from this repo |
|---|---|---|
| Website — x402charity.com | Vercel (project linked to allscale-io/x402charity, auto-deploys from main) |
The static landing page + dashboard (docs/) and the API endpoints (api/index.ts → wraps @x402charity/server). The Vercel build copies docs/{index.html, colors_and_type.css, x402-charity.js, assets/, fonts/} into public/, and serverless rewrites send /donate, /donations, /address, /charity, /health to api/index.ts. |
npm package — x402charity |
npm registry | Built from packages/core/. Includes the X402CharityClient, the Express + Next.js middleware, the registry helpers, and the npx x402charity CLI. |
| GitHub repo — allscale-io/x402charity | GitHub | This repo. |
A second internal package (@x402charity/server, in packages/server/) is the Express app the Vercel function and the Dockerfile both run. It is not published to npm — it's a workspace-only package used by the Vercel deploy and anyone running pnpm dev / docker run x402charity.
x402charity/
├── packages/
│ ├── core/ # npm package "x402charity" — client, middleware, CLI
│ └── server/ # Express donation server (not on npm; used by Vercel + Docker)
├── registry/
│ └── charities.json # Charity directory
├── docs/ # Source of the live website. All files here get copied to public/ at build time.
│ ├── index.html # Landing page + dashboard markup
│ ├── colors_and_type.css # AllScale design-system tokens
│ ├── x402-charity.js # Frontend logic (live feed, dashboard, game, copy buttons)
│ ├── assets/ # Logo, chain & token icons
│ │ ├── allscale-logo.svg
│ │ ├── chain/solana.svg
│ │ └── tokens/{usdc,sol}.svg
│ └── fonts/Archivo-VariableFont.ttf # Brand font
├── api/
│ └── index.ts # Vercel serverless entry point (wraps the Express app)
├── public/ # GENERATED at build time by `vercel.json`. Do not edit. Gitignored except .gitkeep.
├── Dockerfile
└── vercel.json # Vercel build/rewrite config
The Solana port is recent. The following items are known gaps or follow-ups — contributions welcome.
solana-devnet with the default x402.org facilitator. /health, /charity, /address, /donations all respond; static assets serve correctly; POST /donate against an unfunded wallet fails fast with {"error":"Donation failed","details":"x402 donation failed (402): ..."} rather than hanging.https://x402.org/facilitator/supported advertises Solana devnet (CAIP-2 solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1) and returns a feePayer of CKPKJWNdJEqa81x7CkZ14BVPiY6y16Sxs7owznqtWYp5 — confirming facilitator-as-fee-payer mode is wired correctly.faucet.circle.com (Solana → Devnet), POST /donate, and confirm the receipt contains a real Solana signature visible on Solscan.@x402/svm is expected to include a createAssociatedTokenAccount instruction in the partial transaction when the charity ATA does not exist, with the facilitator paying the ~0.002 SOL rent. This has not been confirmed against a charity wallet that has never held USDC. Workaround: pre-create the charity ATA with spl-token create-account if the first donation fails.https://x402.org/facilitator currently advertises Solana devnet only. Booting with DONATION_NETWORK=solana-mainnet and no FACILITATOR_URL will crash at startup with Facilitator does not support scheme "exact" on network "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp". To use mainnet today, set FACILITATOR_URL=https://facilitator.payai.network (or another mainnet-capable facilitator) — the server now supports this override./donations RPC quota. Donation history is reconstructed from getSignaturesForAddress(charityATA) + getTransaction() per signature. Public Solana RPCs (api.mainnet-beta.solana.com, api.devnet.solana.com) throttle aggressively. Expect failures or partial results above a few requests per minute. Plug in a Helius / QuickNode / Triton RPC URL by extending packages/server/src/server.ts to read SOLANA_MAINNET_RPC / SOLANA_DEVNET_RPC env vars and pass them to createSolanaRpc(...)./donations query semantics changed. The previous EVM version accepted ?daysAgo=N and scanned a calendar day of blocks. The Solana version accepts ?limit=N (default 50, max 200) and returns the last N signatures touching the charity ATA. Any client that hard-coded daysAgo needs to be updated.POST /donate serializes calls and retries up to 3× with a 1 s delay. On EVM this guarded against nonce conflicts; on Solana (facilitator-as-fee-payer, ~400 ms finality) it is largely redundant and adds latency. It is safe but could be simplified.registry/charities.json currently contains one placeholder entry (GokT7XLkr4ezHGB6KrLwTGyhCSVF8YJaqbVf2ZNeAJxr on devnet) used only as a fallback. Replace with a real testing charity wallet before promoting the demo, and document the registry submission flow for Solana charities.x402charity package on npm is the EVM version (viem + @x402/evm). Bump to a new major (this is a breaking API change — middleware factories are now async, and the secret-key format changed) and publish.@x402/svm peer-dep pin. @solana/kit is pinned at ^5.5.1 to match the version @x402/svm@2.11.0's nested @solana-program/token@0.9.0 was built against. Once @x402/svm publishes a release built against @solana/kit@^6.x, bump both.PLAN.md, ISSUES_AND_FIXES.md, and PROMOTION_STRATEGY.md have disclaimers at the top noting they predate the Solana migration. Rewrite (or delete) them when convenient.Contributions welcome. Please open an issue first to discuss what you'd like to change.
To add a charity to the public registry, submit a PR editing registry/charities.json:
{
"id": "your-charity-id",
"name": "Your Charity Name",
"description": "What the charity does",
"walletAddress": "So11111111...",
"chain": "solana-mainnet",
"verified": false,
"category": "education",
"x402Endpoint": "https://your-charity-server.com/donate"
}
MIT
Open contract-facing SDK for payable routes and gateway-backed integrations. Thin public surface for authorize, checkout, and session flows.
x402 (HTTP 402 Payment Required) SDK + MCP server: let any API charge for itself and any AI agent pay for itself, USDC & stablecoins across EVM, Solana & 8 more chain families, in a couple of lines. Backendless, no fee, self-custodial, paid straight to your wallet. TypeScript, MIT.
⚡ The gold standard for x402 resources. 300+ projects, SDKs, tools, facilitators, and ecosystem data for the HTTP 402 Payment Required protocol. Curated by 24K Labs.
Enterprise audit, compliance & budget enforcement layer for the x402 payment protocol
Open Source x402 API Router. Instantly turn any API into a USDC pay-per-request Service for AI Agents.
x402 service provider tooling for Azeth — gate Hono endpoints behind x402 payments
A payments protocol for the internet. Built on HTTP.
Self-healing infrastructure for AI agent payments. 90.3% auto-recovery.
Daydreams is a set of tools for building agents for commerce
The best way to monetize AI applications & MCP, using x402, CDP Smart Wallets & Paymaster
URL shortener
AWS payment demo of x402 using Bedrock AgentCore, Strands SDK, and CloudFront.