Stripe for AI Agents • EZ-Pass for the API Economy
Meter in sats per request. No accounts. No bank required.
Python SDK • JS SDK • Docker • Live Demo
An AI agent pays 1 sat for API access — in real-time
Card rails aren't built for per-request payments. Fixed minimums make micropayments uneconomic.
Illustrative example:
An AI agent needs 50 API calls to research a topic.
Card rails: ~$15 in minimum fees (50 × ~$0.30)
Value: $0.50 total
That's 3,000% overhead — broken unit economics.
Agents can't "create accounts and enter card details" per tool call — so developers fall back to API keys, subscriptions, and rate limits.
SatGate solves this with sats-native per-request pricing (L402). Agents pay and authenticate without accounts.
| Use Case | What SatGate Does |
|---|---|
| Monetize APIs per request | Sub-cent pricing that's impossible on card rails. Charge 1 sat per call. |
| Secure agent traffic with paid capabilities | L402 tokens replace accounts/API keys. No PII, no credential stuffing. |
Bonus: High-volume scraping becomes expensive and self-limiting. (Economic friction for L7 abuse — use alongside your WAF/CDN for volumetric protection)
This is the open-source SatGate proxy, SDKs, and documentation.
| Directory | Description |
|---|---|
proxy/ |
L402 proxy (Aperture config + Node.js) |
sdk/ |
Python, JavaScript, Go SDKs |
docker/ |
One-click Docker deployment |
deploy/ |
Cloud deployment configs (Railway, etc.) |
docs/ |
Architecture, security model, guides |
examples/ |
Demo scripts |
cli/ |
CLI tools for token inspection |
satgate-landing/ |
satgate.io marketing site |
pip install satgatefrom satgate import SatGateClient, LNBitsWallet
# Create a session with your Lightning wallet
wallet = LNBitsWallet(url="https://legend.lnbits.com", admin_key="...")
client = SatGateClient(wallet)
# That's it. 402s are handled automatically.
response = client.get("https://api.example.com/premium/data")
print(response.json())pip install satgate[langchain]from satgate import SatGateTool, LNBitsWallet
from langchain.agents import initialize_agent, AgentType
from langchain_openai import ChatOpenAI
# Give your AI agent a wallet
wallet = LNBitsWallet(url="...", admin_key="...")
tools = [SatGateTool(wallet=wallet)]
agent = initialize_agent(tools, ChatOpenAI(), agent=AgentType.OPENAI_FUNCTIONS)
# Let it roam the paid API economy
agent.run("Fetch the premium market report")npm install @satgate/sdkimport { SatGateClient } from '@satgate/sdk';
const client = new SatGateClient({ wallet: 'webln' });
// Automatic payment handling via WebLN (Alby)
const response = await client.get('https://api.example.com/premium');
console.log(await response.json());go get github.com/SatGate-io/satgate/sdk/goimport satgate "github.com/SatGate-io/satgate/sdk/go"
wallet := satgate.NewLNBitsWallet("https://legend.lnbits.com", "admin-key")
client := satgate.NewClient(wallet)
// 402 → Pay → Retry happens automatically
resp, _ := client.Get("https://api.example.com/premium")git clone https://github.com/SatGate-io/satgate.git
cd satgate/docker
cp env.example .env
# Edit .env with your LNC credentials
docker compose -f docker-compose.full.yml up -d# 1. Clone
git clone https://github.com/SatGate-io/satgate.git
cd satgate
# 2. Install
npm install
# 3. Configure Aperture (edit proxy/aperture.yaml)
# Add your LNC credentials to the authenticator section:
# authenticator:
# passphrase: "your-10-word-lnc-phrase"
# mailboxaddress: "mailbox.terminal.lightning.today:443"
# network: "mainnet"
# 4. Start the backend
node proxy/server.js
# 5. Start Aperture (in another terminal)
aperture --configfile=proxy/aperture.yaml
# 6. Test it
curl http://localhost:8081/api/free/ping # ✅ Free
curl http://localhost:8081/api/micro/ping # ⚡ 402 → Pay 1 sat
⚠️ Security: Keep secrets in config files (with proper permissions), not CLI flags. CLI args leak via process listings (ps aux). Ensureaperture.yamlis not committed to version control.
| Endpoint | Price | Use Case |
|---|---|---|
/api/micro/* |
1 sat | True micropayments |
/api/basic/* |
10 sats | High-volume |
/api/standard/* |
100 sats | Analytics |
/api/premium/* |
1000 sats | AI inference |
/api/free/* |
Free | Health checks |
Sats-first pricing. We quote and settle in satoshis. Display an optional real-time fiat estimate in your UI if needed.
Configure in proxy/aperture.yaml:
services:
- name: micro
pathregexp: '^/api/micro($|/.*)$'
price: 1 # 1 satoshi
timeout: 86400┌─────────────┐ 402 + Invoice ┌──────────────┐ Forward ┌─────────────┐
│ Client │◄────────────────────►│ SatGate │◄───────────────►│ Your API │
│ (Human/AI) │ L402 Token │ (Aperture) │ Validate │ (Backend) │
└─────────────┘ └──────────────┘ └─────────────┘
│ │
│ ⚡ Pay Invoice │
└────────────────────────────────────┘
Lightning Network
- 402 Response — Client requests protected endpoint, gateway returns
HTTP 402with a Lightning invoice - Pay Invoice — Client pays invoice via Lightning, receives cryptographic preimage
- L402 Token — Client combines macaroon + preimage into an
Authorization: L402header for access
L402 Token = Macaroon + Preimage — A bearer credential with embedded permissions (caveats) that proves payment.
SatGate never holds your funds. We help generate invoices, but payments settle directly to your Lightning node (or your partner custodian). We never hold your keys.
Traditional APIs use identity-based access: "Prove who you are, then we decide what you can do."
SatGate uses capability-based access: "Present a token that already encodes what you can do."
| Identity-Based (OAuth/API Keys) | Capability-Based (L402) | |
|---|---|---|
| Model | Who you are | What you hold |
| Requires | User databases, PII | Cryptographic tokens |
| Risk | Credential stuffing, breaches | Token theft (mitigated by short-lived caveats) |
| For Agents | ❌ Can't sign up | ✅ Just present token |
- No Accounts Required — Access via L402 bearer tokens (macaroons + proof-of-payment), not usernames or API keys
- Edge Verification — Tokens verified cryptographically at the gateway; no centralized identity store needed (usage accounting/quotas can be tracked without storing PII)
- Least Privilege — Add caveats to constrain scope, time, audience, and budget (e.g.,
"valid_until": 5min,"max_calls": 10) - Economic Friction for L7 Abuse — High-volume scraping becomes expensive and self-limiting; use alongside WAF/CDN for volumetric protection
- Privacy-Forward — Zero PII collection; reduced credential-stuffing exposure with short-lived scoped tokens
The security primitive: L402 creates paid capabilities — cryptographic tokens where payment gates issuance and the token itself encodes permissions.
SatGate is a Zero Trust Policy Enforcement Point — the gateway that verifies every protected request and enforces scoped access via L402/macaroons.
- Per-request verification — Every protected call requires a valid L402 token; no network trust assumptions
- Continuous authorization — Token validated on each request, not just at session start
- Least privilege by design — Macaroon caveats constrain scope, time, and budget
- Reduced trust dependencies — Cryptographic verification without centralized user databases
✅ Zero Trust PEP for API access
✅ Complements existing security stack (WAF/CDN, rate limiting, SIEM)
⚠️ Not a full Zero Trust program (identity governance, device posture, microsegmentation)
In the agent era, switching APIs isn't a two-week integration project. Agents can evaluate providers per request and route based on price, latency, and availability.
This enables an API marketplace where providers compete per request.
from satgate import SatGateSession
import time
# Define providers (each running SatGate)
PROVIDERS = [
{"name": "Provider A", "url": "https://api-a.example.com/data", "price_sats": 5},
{"name": "Provider B", "url": "https://api-b.example.com/data", "price_sats": 8},
{"name": "Provider C", "url": "https://api-c.example.com/data", "price_sats": 3},
]
def fetch_with_failover(session, providers, timeout=5):
"""Try providers in order; failover on error/timeout."""
# Sort by price (or add latency, reputation, etc.)
sorted_providers = sorted(providers, key=lambda p: p["price_sats"])
for provider in sorted_providers:
try:
print(f"Trying {provider['name']} ({provider['price_sats']} sats)...")
start = time.time()
# SatGate handles 402 → pay → retry automatically
response = session.get(provider["url"], timeout=timeout)
if response.ok:
latency = time.time() - start
print(f"✓ Success via {provider['name']} ({latency:.2f}s)")
return response.json()
except Exception as e:
print(f"✗ {provider['name']} failed: {e}")
continue # Try next provider
raise Exception("All providers failed")
# Usage
session = SatGateSession(wallet=my_wallet)
data = fetch_with_failover(session, PROVIDERS)- Agent sorts providers by price (cheapest first)
- Tries Provider C (3 sats) — if down, moves to next
- Tries Provider A (5 sats) — SatGate handles 402 → pay → access
- If timeout/error → automatically tries Provider B (8 sats)
The agent switches providers on the next call — no human intervention, no config changes.
| Without SatGate | With SatGate |
|---|---|
| Each provider needs separate API key | One wallet works everywhere |
| Signup/onboarding per provider | Pay-to-authorize instantly |
| Days to add a new provider | Seconds to failover |
| Static pricing (contracts) | Dynamic per-request pricing |
The primitive: SatGate's L402 tokens are provider-agnostic. Any provider running SatGate accepts the same pay → token → call pattern.
satgate/
├── README.md # You are here
├── LICENSE # MIT
├── proxy/ # Gateway (Aperture config + Node.js backend)
│ ├── aperture.yaml # Pricing configuration
│ ├── server.js # API endpoints
│ └── nginx/ # Production configs
├── sdk/
│ ├── python/ # Python SDK + LangChain Tool
│ └── js/ # JavaScript SDK + TypeScript
├── docker/ # One-click deployment
│ ├── docker-compose.full.yml
│ └── env.example
├── examples/ # Demo scripts
│ └── hero_demo.py # The "money shot" demo
└── docs/ # Documentation & pitch decks
-
Lightning Node with LNC enabled:
-
LNC Pairing Phrase:
- Go to Terminal Web
- Create new LNC session
- Copy your 10-word phrase
python examples/hero_demo.pyWatch an AI agent autonomously pay for API access in real-time.
For live demos, see the Demo Commands:
- 🔐 Crawl — Capability token commands (no crypto required)
- 💰 Run — L402 payment demo
- 🛠️ Any-device curl commands (works from borrowed laptops)
- 🔍 Token inspection and governance tools
| Error | Solution |
|---|---|
| "Self-payment not allowed" | Use a different wallet than your node |
| "Cannot find payment route" | Need inbound liquidity (Voltage Flow, LN+) |
| "L402 has expired" | Restart Aperture to refresh macaroons |
| CORS errors | Ensure Aperture is running on port 8081 |
- Demo Commands — Quick reference for live demos
- Architecture — Technical deep dive
- L402 Response Schema — Machine-friendly 402 response format
- llms.txt — Machine-readable spec for AI assistants
- L402 Protocol Spec
- Aperture Docs
- WebLN Guide
- Voltage Cloud
PRs welcome! See CONTRIBUTING.md for guidelines.
MIT License — See LICENSE
© 2025 SatGate. Patent Pending.
Stripe for AI Agents • EZ-Pass for the API Economy
satgate.io
