Documentation
Financial rails for autonomous agents. Merchants create invoices. Agents pay them. Everything in between is handled by the protocol.
Two Roles, One Protocol
Merchants are API providers — developers who gate endpoints behind micro-payments. They create invoices server-side with a Merchant Key and receive payouts.
Agents are autonomous callers — bots, scripts, or AI systems that encounter paywalls and pay them automatically using an Agent Wallet backed by a verified card.
Tamper-Proof Pricing
Amount and destination are locked at invoice creation. The agent can only pay what the merchant defined — nothing is mutable from the agent side.
Burn-on-Verify Receipts
Each receipt can only be verified once. The first successful read marks it redeemed. Replay attacks are blocked at the protocol level.
Balance-First Settlement
The protocol checks the agent's pre-funded balance before charging the card. High-frequency agents can run entirely on balance.
Cryptographic Identity
Optional up2d daemon ties payments to specific hardware. Unverified callers are blocked even if they have a valid API key.
Base URLs
# Merchant API (invoice creation, keys, dashboard) https://payments.up2.cash # Agent API (wallet, pay-invoice) https://payments.up2.cash # Dashboard https://dashboard.up2.cash
Get a merchant invoice created and paid by an agent in under 5 minutes.
Step 1 — Merchant creates an invoice
import requests headers = {"X-Merchant-Key": "mk_live_YOUR_KEY"} payload = { "amount": 0.50, "billing_mode": "per_use", "content_id": "inference_v1" } r = requests.post( "https://payments.up2.cash/api/merchant/create-invoice", json=payload, headers=headers ) invoice_id = r.json()["invoice_id"] print(invoice_id) # e.g. "3e7c-a9f2-..."
Step 2 — Agent pays the invoice
pay_r = requests.post( "https://payments.up2.cash/api/agent/pay-invoice", json={ "invoice_id": invoice_id, "api_key": "ak_live_YOUR_WALLET_KEY" } ) print(pay_r.json()) # { # "status": "success", # "paid_via": "balance", # "deducted": 0.50, # "remaining_balance": 4.50 # }
Step 3 — Merchant verifies the receipt
verify_r = requests.get( f"https://payments.up2.cash/api/check-status/{invoice_id}" ) data = verify_r.json() if data["status"] == "success": print("✅ Payment verified — serve the content") else: print("❌ Not paid — block access")
/api/check-status/{id} marks it redeemed. A second call returns 403. Build your system to check once and cache the result.Full onboarding required before invoices can settle to your bank.
Register at dashboard.up2.cash/start
Provide your name, email, phone (OTP verified), and password. Both phone and email are verified before account creation.
Complete Onboarding
Submit identity verification (DOB, SSN last 4, address) and connect a bank account. Required for payouts to enable. Business accounts require a company representative.
Generate a Merchant Key
From the dashboard → API Keys → Create Key. You'll receive a mk_live_... key. Store it server-side only. Max 5 active keys per account.
Use your Merchant ID in agent instructions
Your masked Merchant ID (upsqrd_live_...) can be shared with agents to target your account for payments via the generate-payment-link endpoint.
mk_live_...) are long-lived server-to-server credentials. Never expose them in frontend code, client-side scripts, or agent prompts. Rotate them via the dashboard if compromised.All merchant endpoints. Auth via X-Merchant-Key header or Firebase Bearer token.
Create Invoice
Creates a payable invoice server-side. Amount and destination are immutable after creation.
| Field | Type | Required | Description |
|---|---|---|---|
amount | float | REQUIRED | Invoice amount in USD. Minimum $0.50. |
billing_mode | string | optional | "per_use" (default) or "metered" |
content_id | string | optional | Your internal identifier for the gated resource. |
meter_deposit | float | optional | For metered mode: deposit size. Default $5.00. |
pass_fees | bool | optional | Pass processing fees to agent. Default false. |
request_url | string | optional | Tag which endpoint triggered this invoice. |
metadata | object | optional | Custom key/value data stored with the invoice. |
{
"invoice_id": "3e7c-a9f2-...",
"amount": 0.50,
"billing_mode": "per_use",
"payment_url": "https://payments.up2.cash/checkout?q=...",
"merchant_id": "upsqrd_live_..."
}
Check Transaction Status
Verify payment and burn the receipt in a single atomic operation. Call once. Cache the result.
{
"status": "success",
"amount": 0.50,
"currency": "usd",
"merchant_acct": "upsqrd_live_..."
}
{
"status": "error",
"detail": "Receipt already used. Replay verification denied."
}
How to gate your API endpoints behind UP² payments. The 402 pattern — the standard way to tell an agent "pay first, then retry."
The 402 Paywall Pattern
When an agent hits your endpoint without valid payment, return 402 Payment Required with an invoice. The agent pays it, then retries with a proof header.
import requests from fastapi import FastAPI, Header, HTTPException from fastapi.responses import JSONResponse app = FastAPI() UP2_MERCHANT_KEY = "mk_live_YOUR_KEY" UP2_API = "https://payments.up2.cash" PRICE_USD = 0.50 def create_invoice(content_id: str): r = requests.post( f"{UP2_API}/api/merchant/create-invoice", json={"amount": PRICE_USD, "content_id": content_id}, headers={"X-Merchant-Key": UP2_MERCHANT_KEY} ) return r.json() def verify_payment(invoice_id: str) -> bool: r = requests.get(f"{UP2_API}/api/check-status/{invoice_id}") return r.json().get("status") == "success" @app.post("/api/my-endpoint") async def my_gated_endpoint( x_payment_token: str = Header(None, alias="X-Payment-Token") ): # 1. Check for proof of payment if x_payment_token and verify_payment(x_payment_token): return {"result": "your gated content here"} # 2. No payment — create invoice and return 402 invoice = create_invoice("my-endpoint") return JSONResponse( status_code=402, content={ "error": "Payment Required", "invoice_id": invoice["invoice_id"], "amount": PRICE_USD, "pay_url": invoice["payment_url"] } )
invoice_id at /api/agent/pay-invoice → retries your endpoint with X-Payment-Token: {invoice_id}. Your endpoint calls check-status to verify. Serve content if paid.An Agent Wallet is a verified card linked to an API key. Two-step setup: create a SetupIntent, verify with your bank, receive your key.
Go to dashboard.up2.cash/signup
Verify your email address. You'll receive a session token used for the setup flow.
Complete 3D Secure
Your bank sends an SMS or app push. Confirm it. This proves you own the card and authorizes UP² to charge it off-session.
Receive API key
On success you receive your ak_live_... key. Store it securely — it's shown once.
Default Wallet Limits
| Setting | Default | Description |
|---|---|---|
daily_limit | $50.00 | Max spend per calendar day. |
max_tx_limit | $5.00 | Max per single transaction. |
whitelist_enabled | false | Strict Mode — domain/IP allowlist. |
identity_required | false | Require up2d daemon signature. |
is_paused | false | Global pause switch. |
whitelist_enabled is false, the protocol enforces hard caps: max $5.00 per transaction, max $100.00 daily — regardless of your configured limits. Enable Strict Mode to unlock higher limits.The single endpoint your agent calls at runtime to execute payments.
Pay Invoice
The core agent payment endpoint. Checks balance first — deducts if available, charges card if not.
| Field | Type | Required | Description |
|---|---|---|---|
invoice_id | string | REQUIRED | ID returned by merchant's create-invoice. |
api_key | string | REQUIRED | Your ak_live_... wallet key. |
{
"status": "success",
"receipt": "3e7c-a9f2-...",
"paid_via": "balance",
"deducted": 0.50,
"remaining_balance": 4.50
}
{
"status": "success",
"receipt": "3e7c-a9f2-...",
"paid_via": "card",
"pi_id": "pi_...",
"remaining_balance": 0
}
Error Codes
| Status | Meaning |
|---|---|
401 | Invalid API key. |
402 | Daily or per-transaction limit exceeded. |
403 | Wallet paused, domain not whitelisted, or identity check failed. |
404 | Invoice not found. |
The full execution logic for autonomous agents clearing UP² paywalls. This is the reference implementation.
Phase Overview
Full Protocol Implementation
import requests API_KEY = "ak_live_YOUR_KEY" PAY_ENDPOINT = "https://payments.up2.cash/api/agent/pay-invoice" # In-memory receipt store: { domain: invoice_id } _receipt_store = {} def up2_request(method: str, url: str, **kwargs): """ Drop-in wrapper for requests.get/post that handles UP² paywalls. Returns the final response or raises on failure. """ from urllib.parse import urlparse domain = urlparse(url).netloc headers = kwargs.pop("headers", {}) # Phase 0: inject known receipt if domain in _receipt_store: headers["X-Payment-Token"] = _receipt_store[domain] # Phase 1: attempt request r = requests.request(method, url, headers=headers, **kwargs) if r.status_code != 402: return r # 200 or other — not our problem # Phase 2: extract invoice data = r.json() invoice_id = data.get("invoice_id") if not invoice_id: raise ValueError("402 response missing invoice_id") print(f"💸 Paywall detected. Paying invoice {invoice_id}...") # Phase 3: pay pay_r = requests.post( PAY_ENDPOINT, json={"invoice_id": invoice_id, "api_key": API_KEY} ) pay_r.raise_for_status() receipt = pay_r.json().get("receipt") # Cache receipt for this domain _receipt_store[domain] = receipt # Phase 4: retry with receipt header headers["X-Payment-Token"] = receipt return requests.request(method, url, headers=headers, **kwargs) # Example usage: r = up2_request("POST", "https://someapi.com/api/inference", json={"prompt": "hello"}) print(r.json())
Two billing modes built into every invoice. Set at invoice creation time by the merchant.
Per Use
Each invoice is a discrete charge. The protocol checks the agent's balance first — if funded, deducts atomically. If the balance is dry, charges the card directly.
Best for: inference endpoints, classification APIs, one-time data pulls, anything with a clear unit price.
Metered
The agent pre-loads a deposit via card. That deposit lives as a balance scoped to that merchant. Subsequent per-use calls drain from the balance — minimizing individual card charges and reducing processing overhead for high-frequency agents.
Best for: compute leases, streaming APIs, long-running autonomous tasks.
Settlement Resolution
Platform Fees
| Fee Type | Amount | Notes |
|---|---|---|
| Variable rate | 6% | Per transaction |
| Fixed fee | $0.30 | Per card charge |
| Pass fees to agent | Optional | Set pass_fees: true at invoice creation |
Layered security: spending limits, domain allowlists, IP restrictions, and cryptographic device identity via up2d.
Trust Tiers
Trust tiers are determined by up2d — the identity daemon that runs on your machine and signs every payment request with hardware-bound cryptography. The tier your device qualifies for is detected automatically. Learn more about up2d ↗
| Tier | Method | Key Storage |
|---|---|---|
| Hardened | Linux + TPM 2.0 | Hardware — unextractable |
| Secure | macOS Keychain / Windows DPAPI | OS-bound to the machine |
| Standard | Software RSA keypair | On-disk, device-bound |
Enforcement Order
Pause Check
If is_paused: true, all payments blocked. Instant kill switch.
Identity Check
If identity_required: true, request must include valid HMAC from an up2d daemon. Unverified callers blocked even with a valid API key.
Domain / IP Allowlist
If whitelist_enabled: true, the merchant's domain or Merchant ID must be in your allowlist. IP whitelist checked separately.
Spending Limits
Per-transaction cap and daily spend limit enforced. With Strict Mode off, hard caps of $5.00/tx and $100.00/day apply regardless of configured limits.
Get up2d and read the full documentation ↗
Real integration patterns. Copy, adapt, deploy.
Gated Image Generation API
Full example: an agent calls an image API, hits a paywall, pays it, and retries to get the image URL.
import requests TARGET = "https://yourapi.com/endpoint" PAY_ENDPOINT = "https://payments.up2.cash/api/agent/pay-invoice" WALLET_KEY = "ak_live_YOUR_KEY" def get_image(prompt: str): payload = {"prompt": prompt, "quality": "high"} # 1. Initial attempt r1 = requests.post(TARGET, json=payload) if r1.status_code == 402: invoice_id = r1.json()["invoice_id"] # 2. Pay invoice r2 = requests.post(PAY_ENDPOINT, json={ "invoice_id": invoice_id, "api_key": MY_API_KEY }) r2.raise_for_status() # 3. Retry with receipt r3 = requests.post( TARGET, json=payload, headers={"X-Payment-Token": invoice_id} ) return r3.json().get("image_url") return r1.json().get("image_url") print(get_image("a robot paying for things, neon, 8k"))
from fastapi import FastAPI, Header from fastapi.responses import JSONResponse import requests app = FastAPI() MERCHANT_KEY = "mk_live_YOUR_KEY" UP2 = "https://payments.up2.cash" def issue_invoice(): r = requests.post(f"{UP2}/api/merchant/create-invoice", json={"amount": 0.50, "content_id": "endpoint"}, headers={"X-Merchant-Key": MK}) return r.json() def paid(token: str) -> bool: if not token: return False r = requests.get(f"{UP2}/api/check-status/{token}") return r.json().get("status") == "success" @app.post("/api/endpoint") async def draw(body: dict, x_payment_token: str = Header(None)): if not paid(x_payment_token): inv = issue_invoice() return JSONResponse(402, { "error": "Payment Required", "invoice_id": inv["invoice_id"], "amount": 0.50 }) # Generate and return image... return {"success": True, "image_url": "https://..."}
Copy these into your agent's system prompt or context files. They teach the agent how to handle UP² paywalls without manual intervention.
YOUR_KEY_HERE with a real wallet key.Generic Payment Protocol
UP² Payment Protocol (v3.1)
Overview
This protocol defines the lifecycle of an agent clearing a UP² paywall. It uses a Wallet-First approach: try passive deduction from existing balance before falling back to a card charge.
Configuration
- Wallet API Key:
ENTER YOUR KEY HERE - Payment Endpoint:
POST https://payments.up2.cash/api/agent/pay-invoice - Proof Header:
X-Payment-Token
Phase 0 — Preflight
Maintain a memory map of Domain → Invoice ID across requests. If a paid receipt exists for the target domain, inject it as X-Payment-Token before every request.
Phase 1 — Passive Attempt
Make the request normally. If 200 OK → done. If 402 Payment Required → proceed to Phase 2.
Phase 2 — Extract Invoice
From the 402 JSON response, extract: invoice_id and amount.
Phase 3 — Pay
POST https://payments.up2.cash/api/agent/pay-invoice
{
"invoice_id": "EXTRACTED_INVOICE_ID",
"api_key": "ENTER YOUR KEY HERE"
}
Store the returned receipt mapped to the domain.
Phase 4 — Retry
Resend the original request with X-Payment-Token: {receipt}. The body must be identical to the original call.
Common Errors
- Do not treat 402 as a hard failure — it is a payment prompt
- Always replay the original payload on retry
- Do not send the token in the request body — it goes in the header
- Use timeouts of at least 60s for generation endpoints
Endpoint-Specific Guide Template
[Endpoint Name] — Agent Integration Guide
Endpoint
POST /api/[your-endpoint]
Request
Headers:
Content-Type: application/json
X-Payment-Token: <invoice_id> (only on retry)
Body:
{
"param1": "value",
"param2": "value"
}
Success Response — 200
{
"success": true,
"result": "..."
}
Payment Required — 402
{
"error": "Payment Required",
"invoice_id": "inv_xxx",
"amount": 0.50
}
Required Agent Behavior on 402
- Pay the invoice using UP² Agent Wallet
- Retry with identical body
- Send
X-Payment-Token: inv_xxxin retry header
Integration Errors
- Missing
Content-Type - Not retrying after payment
- Token sent in body instead of header
- HTTP timeout too short (use 60s+)
Questions
Common questions about the UP² protocol, billing, and integration.
General
Merchants
invoice_id and amount. Create the invoice server-side first using your Merchant Key, then return its ID in the 402 response. See the Integration Guide for the full pattern./api/check-status/{id} marks the receipt as redeemed. A second call returns 403. This is intentional — it prevents replay attacks where the same receipt is used to unlock content multiple times. Cache your verification result.pass_fees: true at invoice creation.upsqrd_live_...) can be included in agent instructions so the agent knows which merchant to target. It can also be added to an agent wallet's domain allowlist as an alternative to URL-based whitelisting.Agent Wallets
whitelist_enabled) off, hard caps of $5.00 per transaction and $100.00 per day are enforced regardless of your configured limits. With Strict Mode on, you can set higher limits and restrict payments to specific domains or IPs. It's a safety default for new wallets.Security
identity_required on their wallet whitelist — meaning they only accept payments from verified machines. For most integrations it's optional.