Overview
SplitStream is a pay-per-use layer on Circle's Arc L1. Anyone can list a service — a piece of content (article, song, photo) or a paid API — and get paid per use in USDC, with the payment split across every contributor on their own chain. Buyers can be humans or AI agents; agents pay per call via the x402 standard.
Register content or an API endpoint with a price and a revenue split. Integrate nothing — we are the paywall.
A human clicks, or an AI agent pays autonomously per call in USDC. The split settles to all owners across chains.
Core concepts
- Piece — the unit you list.
kindisarticle·photo·song·podcast(content) orapi(a paid endpoint). - Split — contributors each take a share in basis points (must sum to 10000 = 100%); each is paid on their
targetChain. - x402 — the HTTP "402 Payment Required" flow agents use to pay per call: request → 402 challenge → pay USDC → retry with proof → get result.
- Credential injection — for authenticated APIs, you store the upstream key once; we inject it per call. The buyer gets access, never the key (no KYC).
1. Get an API key
Open a publisher account once to get a scoped key (the demo key arc_test_sk_demo_0001 works out of the box).
curl -X POST localhost:8787/trpc/tenants.signup \
-H 'content-type: application/json' \
-d '{"name":"Acme Media","onchainAddress":"0xYourArcAddress0000000000000000000000000"}'
# → { apiKey: "arc_test_sk_...", ... } (shown once)2. List content (pay-per-piece, cross-chain split)
A reader pays a few cents to unlock; the price fans out to every contributor on their chain. Use the /publish form, or the API:
curl -X POST localhost:8787/api/v1/pieces \
-H 'content-type: application/json' -H 'x-api-key: arc_test_sk_demo_0001' \
-d '{
"title": "The Stablecoin Frontier",
"kind": "article",
"priceUSDC": "0.05",
"contributors": [
{ "role":"writer", "address":"0x1111…", "targetChain":"base", "splitBps":6000 },
{ "role":"editor", "address":"0x2222…", "targetChain":"arbitrum", "splitBps":2500 },
{ "role":"photographer", "address":"0x3333…", "targetChain":"ethereum", "splitBps":1500 }
]
}'It's now live in the catalog and shareable at /piece/<id>.
3. List a paid API (x402 pay-per-call)
Register any HTTP endpoint with a per-call price. You integrate nothing — SplitStream becomes the x402 paywall and proxies the call on payment.
curl -X POST localhost:8787/api/v1/pieces \
-H 'content-type: application/json' -H 'x-api-key: arc_test_sk_demo_0001' \
-d '{
"title": "My App: FX Rates",
"kind": "api",
"priceUSDC": "0.01",
"endpoint": "https://api.yourapp.com/v1/fx?from=USD&to=EUR",
"httpMethod": "GET",
"contributors": [{ "role":"owner", "address":"0xYourArcEvmAddress", "targetChain":"base", "splitBps":10000 }]
}'Multi-owner APIs split automatically — list several contributors.
4. Authenticated APIs — access without KYC
If your endpoint needs a key, store it once with the piece. It's write-only — never returned by any read endpoint — and injected per call. The paying agent gets the result, never the key.
"auth": { "type":"bearer", "secret":"sk_live_…" }
"auth": { "type":"header", "name":"X-API-Key", "secret":"…" }
"auth": { "type":"query", "name":"apikey", "secret":"…" }Reads expose only authenticated:true and authType — never the secret.
5. Getting paid — real USDC on Arc
- Live (LIVE_X402) — the buyer's USDC payment is verified on Arc, then each owner is paid their split in real USDC on Arc. Proven end-to-end (owner balance 0 → 0.01 on-chain).
- Mirror (default) — keyless demo: simulated settlement so anyone can try it instantly. Split math, credential injection, and live upstream calls are real either way.
- Cross-chain — EVM contributors are paid on Arc directly; other chains route via Circle CCTP / Gateway.
A. Install in your AI (MCP)
Add SplitStream's hosted MCP server to any MCP client (Claude Code, Cursor, …) by URL — no clone, no install. Your AI then has tools to browse and pay for the live catalog; the user just talks normally.
claude mcp add --transport http splitstream https://splitstream-api-production.up.railway.app/mcp
Other clients (Cursor, Windsurf, …): add an HTTP/Streamable MCP server pointing at https://splitstream-api-production.up.railway.app/mcp.
Tools the agent gains: list_pieces, call_api, pay_for_piece (+ treasury tools).
Local dev alternative (needs the repo + Bun): claude mcp add splitstream -- bun run apps/server/src/mcp/stdio.ts
User: "What's the USD→EUR rate right now?"
AI: list_pieces → finds "FX Rate API"
call_api(pieceId) → pays $0.01 → returns { "rates": { "EUR": 0.86 } }
AI: "It's about €0.86 to the dollar."B. x402 — any agent with a wallet
No SplitStream-specific install. An agent with an x402 client + a funded Arc wallet pays our endpoint the standard way. This is the same model the wider x402 ecosystem (incl. pay.sh) uses; Circle's pay-via-agent-wallet does exactly this on Arc.
# 1. request the resource — no payment yet
POST /api/v1/pieces/<id>/call
→ 402 Payment Required
{ "x402Version":1, "accepts":[{
"scheme":"exact", "network":"arc-testnet",
"maxAmountRequired":"10000", "payTo":"0x…", "asset":"0x3600000000000000000000000000000000000000",
"nonce":"0x…", "resource":"/api/v1/pieces/<id>/call" }] }
# 2. pay maxAmountRequired USDC to payTo on Arc (your wallet signs it)
# 3. retry with the proof
POST /api/v1/pieces/<id>/call
X-PAYMENT: base64({ x402Version:1, scheme:"exact", network:"arc-testnet",
payload:{ nonce:"0x…", from:"0xYou", authorization:"<txHash>" } })
→ 200 OK
X-PAYMENT-RESPONSE: base64({ success:true, transaction:"0x…", payer:"0xYou" })
{ "paid":true, "mode":"live-arc", "payments":[…], "upstream":{ "ok":true, "body":{…} } }Try the full handshake locally: pnpm --filter @arcane/server x402:call. The single-use nonce blocks replay.
C. REST / curl (content unlock or known API)
curl -X POST localhost:8787/api/v1/pieces/<id>/pay \
-H 'content-type: application/json' -d '{"payer":"reader"}'
# → { unlock: { contributors:[ …paid per chain… ] } }D. Storefront (human, one click)
Open the storefront: browse pieces, hit Unlock (content) or Pay & call (API), and see the cross-chain fan-out + live result. No account. To pay with your own wallet in real USDC, add Arc first (below).
E. Add Arc Testnet to your wallet
To pay with your own wallet you need Arc Testnet added — most wallets don't have it yet. One click adds it. On Arc, USDC is the gas token, so you only ever need USDC (no separate gas coin).
| Network name | Arc Testnet |
| RPC URL | https://rpc.testnet.arc.network |
| Chain ID | 5042002 |
| Currency symbol | USDC |
| Block explorer | https://testnet.arcscan.app |
| USDC (ERC-20) | 0x3600000000000000000000000000000000000000 |
The button uses your wallet's wallet_addEthereumChain; if it's unavailable, add the values above by hand. Need test USDC? Get it free from the Circle faucet (select Arc Testnet) — it covers both gas and purchases.
Endpoints
| Method | Path | What |
|---|---|---|
| POST | /api/v1/pieces | register a piece (x-api-key) |
| GET | /api/v1/pieces | browse catalog |
| GET | /api/v1/pieces/:id | one piece |
| POST | /api/v1/pieces/:id/pay | unlock content → split |
| POST | /api/v1/pieces/:id/call | x402 pay-per-call (API) |
| POST | /api/v1/pieces/:id/claim | claim after a real wallet payment |
| ALL | /mcp | remote MCP (Streamable HTTP) |
tRPC equivalents: pieces.list / get / create / unlock / callApi, traction.stats, agent.read. MCP tools: list_pieces, call_api, pay_for_piece.
x402 wire format
- 402 body —
{ x402Version, accepts:[ PaymentRequirements ] } - PaymentRequirements —
scheme:"exact", network:"arc-testnet", maxAmountRequired (atomic USDC), payTo, asset, nonce, resource, maxTimeoutSeconds - X-PAYMENT (request header, base64) —
{ x402Version, scheme, network, payload:{ nonce, from, authorization } } - X-PAYMENT-RESPONSE (response header, base64) —
{ success, transaction, network, payer }
Network & modes
- Chain: Arc Testnet · id
5042002· explorertestnet.arcscan.app - USDC (6-dp ERC-20):
0x3600000000000000000000000000000000000000— also Arc's native gas token - Mirror mode (default): keyless, simulated settlement. LIVE_X402: real USDC on Arc (funded relayer).