// Documentation
UP² Agent Protocol
Documentation

Financial rails for autonomous agents. Merchants create invoices. Agents pay them. Everything in between is handled by the protocol.

01MERCHANT
creates invoice
02INVOICE
locked server-side
03AGENT
pays via API key
04BALANCE
checked first
05CARD
fallback charge
06SETTLED
receipt burned

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

endpoints
# Merchant API (invoice creation, keys, dashboard)
https://payments.up2.cash

# Agent API (wallet, pay-invoice)
https://payments.up2.cash

# Dashboard
https://dashboard.up2.cash
// Getting Started
Quickstart

Get a merchant invoice created and paid by an agent in under 5 minutes.

Step 1 — Merchant creates an invoice

python
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

python
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

python
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")
ℹ️
Burn on VerifyReceipts are single-use. The first call to /api/check-status/{id} marks it redeemed. A second call returns 403. Build your system to check once and cache the result.
// Merchants
Account Setup

Full onboarding required before invoices can settle to your bank.

01

Register at dashboard.up2.cash/start

Provide your name, email, phone (OTP verified), and password. Both phone and email are verified before account creation.

02

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.

03

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.

04

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.

⚠️
Key SecurityMerchant Keys (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.
// Merchants
API Reference

All merchant endpoints. Auth via X-Merchant-Key header or Firebase Bearer token.

Create Invoice

POST /api/merchant/create-invoice

Creates a payable invoice server-side. Amount and destination are immutable after creation.

FieldTypeRequiredDescription
amountfloatREQUIREDInvoice amount in USD. Minimum $0.50.
billing_modestringoptional"per_use" (default) or "metered"
content_idstringoptionalYour internal identifier for the gated resource.
meter_depositfloatoptionalFor metered mode: deposit size. Default $5.00.
pass_feesbooloptionalPass processing fees to agent. Default false.
request_urlstringoptionalTag which endpoint triggered this invoice.
metadataobjectoptionalCustom key/value data stored with the invoice.
response 200
{
  "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

GET /api/check-status/{invoice_id}

Verify payment and burn the receipt in a single atomic operation. Call once. Cache the result.

response 200 — paid
{
  "status": "success",
  "amount": 0.50,
  "currency": "usd",
  "merchant_acct": "upsqrd_live_..."
}
response 403 — replay blocked
{
  "status": "error",
  "detail": "Receipt already used. Replay verification denied."
}
// Merchants
Integration Guide

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.

python — fastapi example
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"]
        }
    )
ℹ️
Agent FlowThe agent hits your endpoint → gets 402 → pays 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.
// Agent Wallets
Wallet Setup

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.

01

Go to dashboard.up2.cash/signup

Verify your email address. You'll receive a session token used for the setup flow.

02

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.

03

Receive API key

On success you receive your ak_live_... key. Store it securely — it's shown once.

Default Wallet Limits

SettingDefaultDescription
daily_limit$50.00Max spend per calendar day.
max_tx_limit$5.00Max per single transaction.
whitelist_enabledfalseStrict Mode — domain/IP allowlist.
identity_requiredfalseRequire up2d daemon signature.
is_pausedfalseGlobal pause switch.
⚠️
Strict Mode Off = Hard CapsWhen 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.
// Agent Wallets
Agent API Reference

The single endpoint your agent calls at runtime to execute payments.

Pay Invoice

POST/api/agent/pay-invoice

The core agent payment endpoint. Checks balance first — deducts if available, charges card if not.

FieldTypeRequiredDescription
invoice_idstringREQUIREDID returned by merchant's create-invoice.
api_keystringREQUIREDYour ak_live_... wallet key.
response 200 — paid via balance
{
  "status": "success",
  "receipt": "3e7c-a9f2-...",
  "paid_via": "balance",
  "deducted": 0.50,
  "remaining_balance": 4.50
}
response 200 — paid via card
{
  "status": "success",
  "receipt": "3e7c-a9f2-...",
  "paid_via": "card",
  "pi_id": "pi_...",
  "remaining_balance": 0
}

Error Codes

StatusMeaning
401Invalid API key.
402Daily or per-transaction limit exceeded.
403Wallet paused, domain not whitelisted, or identity check failed.
404Invoice not found.
// Agent Wallets
Payment Protocol

The full execution logic for autonomous agents clearing UP² paywalls. This is the reference implementation.

Phase Overview

0PREFLIGHT
check memory
1PASSIVE
try with key
2402 DETECT
extract invoice
3PAY
call pay-invoice
4RETRY
with receipt

Full Protocol Implementation

python
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())
// Billing
Per Use vs Metered

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.

BILLING_MODE: per_use
MIN: $0.50


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.

BILLING_MODE: metered
DEFAULT DEPOSIT: $5.00


Best for: compute leases, streaming APIs, long-running autonomous tasks.

Settlement Resolution

AGENT CALLS
pay-invoice
IDENTITY
HMAC verify
LIMITS
check caps
BALANCE
deduct first
CARD
if balance empty
SETTLED
receipt burned

Platform Fees

Fee TypeAmountNotes
Variable rate6%Per transaction
Fixed fee$0.30Per card charge
Pass fees to agentOptionalSet pass_fees: true at invoice creation
// Security
Security & Identity

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 ↗

TierMethodKey Storage
HardenedLinux + TPM 2.0Hardware — unextractable
SecuremacOS Keychain / Windows DPAPIOS-bound to the machine
StandardSoftware RSA keypairOn-disk, device-bound

Enforcement Order

1

Pause Check

If is_paused: true, all payments blocked. Instant kill switch.

2

Identity Check

If identity_required: true, request must include valid HMAC from an up2d daemon. Unverified callers blocked even with a valid API key.

3

Domain / IP Allowlist

If whitelist_enabled: true, the merchant's domain or Merchant ID must be in your allowlist. IP whitelist checked separately.

4

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.

🚨
Daemon HMAC Replay WindowDaemon signatures are only valid for 30 seconds from timestamp. Expired signatures are rejected as spoofed even if the HMAC is valid.
🔐
What is up2d? up2d is the background daemon that gives your agent a verifiable, hardware-bound identity. Without it, payment requests carry no cryptographic proof of origin — just an API key. With it, every request is signed by a key that cannot leave your machine.

Get up2d and read the full documentation ↗
// Resources
Code Examples

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.

python — agent side
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"))
python — merchant side (fastapi)
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://..."}
// Resources
Agent MD Files

Copy these into your agent's system prompt or context files. They teach the agent how to handle UP² paywalls without manual intervention.

ℹ️
How to use these filesThese are instruction documents for AI agents — Claude, GPT, custom LLMs, or any autonomous system. Include them in the agent's system prompt, memory, or tool context before it starts making API calls. Replace YOUR_KEY_HERE with a real wallet key.

Generic Payment Protocol

📄 up2-payment-protocol.md

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-integration-guide.md

[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_xxx in retry header

Integration Errors

  • Missing Content-Type
  • Not retrying after payment
  • Token sent in body instead of header
  • HTTP timeout too short (use 60s+)
// FAQ
Frequently Asked
Questions

Common questions about the UP² protocol, billing, and integration.

General

What is the minimum invoice amount?
$0.50 USD. This is Stripe's minimum for card processing. The protocol enforces this server-side — invoices below $0.50 are rejected at creation.
Can the agent change the invoice amount?
No. Amount and destination are locked the moment the merchant creates the invoice. The agent can only pay invoices — they cannot modify them. This is enforced at the protocol level using Firestore transactions.
What currencies are supported?
USD only at this time. Invoices are denominated in US dollars and settled to US bank accounts via Stripe Connect.
How fast does settlement happen?
Balance deductions are atomic and near-instant (typically under 3 seconds). Card charges go through Stripe and are typically settled within 2 business days to the merchant's bank account, depending on payout schedule.

Merchants

How do I trigger the paywall in my API?
Return HTTP 402 with a JSON body containing 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.
Can I verify a receipt more than once?
No. The first call to /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.
When are platform fees charged?
6% + $0.30 per transaction for agent card charges and metered deposits, deducted at settlement. Balance deductions are free — fees are collected at deposit instead. There is also a $0.50 minimum on all agent transactions; amounts below this are rejected at the payment stage. You can pass fees to the agent by setting pass_fees: true at invoice creation.
What is the Merchant ID used for?
The masked Merchant ID (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

Why does wallet setup require 3D Secure?
Card verification confirms you own the card and authorizes UP² to charge it when your agent is running autonomously without a user present. It's a one-time setup step.
What's the difference between Strict Mode on and off?
With Strict Mode (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.
What happens if my balance runs out mid-task?
The protocol falls back to charging your card directly for that transaction. For metered mode, the card charge refills the balance. For per-use mode, it's a direct charge. If the card charge fails, you'll get a 402 response back.
Can I add multiple cards?
You can create up to 5 wallets per 24-hour window, each backed by a different card. Each wallet gets its own API key. You can delete wallets at any time via the dashboard or the delete endpoint.

Security

What is up2d and do I need it?
up2d is an optional background daemon that establishes cryptographic device identity. You only need it if the merchant has enabled identity_required on their wallet whitelist — meaning they only accept payments from verified machines. For most integrations it's optional.
What if my API key is compromised?
Pause your wallet immediately from the dashboard (instant effect). Then delete the wallet to invalidate the card authorization and remove the key from Firestore. Create a new wallet with a new card to get a fresh key.