Up-To Scheme

The upto scheme enables usage-based billing by authorizing transfer of up to a maximum amount, with the actual settlement determined by usage.

Overview

Unlike the exact scheme where the full amount is known upfront, upto allows clients to authorize a maximum payment while only being charged for what they actually use.

Use Cases

  • LLM Token Generation: Authorize $1.00, pay $0.15 for 1,500 tokens
  • Metered API Usage: Pay per request or data volume
  • Streaming Services: Pay per minute/second consumed
  • Compute Resources: Pay per CPU/GPU second

Payment Requirements

The server specifies maximum amount and optional billing configuration:

{
  "scheme": "upto",
  "network": "eip155:8453",
  "maxAmount": "1000000",
  "minAmount": "10000",
  "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
  "payTo": "0x...",
  "maxTimeoutSeconds": 300,
  "extra": {
    "unit": "token",
    "unitPrice": "100",
    "name": "USD Coin",
    "version": "2"
  }
}

Fields

FieldTypeRequiredDescription
schemestringYesAlways "upto"
networkstringYesCAIP-2 network ID (e.g., "eip155:8453")
maxAmountstringYesMaximum authorized amount (smallest units)
minAmountstringNoMinimum settlement amount (prevents dust)
assetstringYesToken contract address
payTostringYesRecipient address
maxTimeoutSecondsnumberYesAuthorization validity period
extra.unitstringNoBilling unit ("token", "request", "second", etc.)
extra.unitPricestringNoPrice per unit

Supported Units

UnitDescriptionExample
tokenAI/LLM tokens1500 tokens @ $0.0001
requestAPI requests100 requests @ $0.01
secondTime-based60 seconds @ $0.001
minuteTime-based5 minutes @ $0.05
byteData volume1MB @ $0.001
kbKilobytes1024 KB
mbMegabytes10 MB

EVM Implementation

On EVM chains, the upto scheme uses EIP-2612 Permit for gasless authorization.

Payment Payload

{
  "t402Version": 2,
  "resource": {
    "url": "https://api.example.com/llm/generate",
    "description": "LLM token generation"
  },
  "accepted": {
    "scheme": "upto",
    "network": "eip155:8453",
    "maxAmount": "1000000",
    "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
    "payTo": "0x...",
    "maxTimeoutSeconds": 300,
    "extra": {
      "name": "USD Coin",
      "version": "2",
      "routerAddress": "0x..."
    }
  },
  "payload": {
    "signature": {
      "v": 28,
      "r": "0x1234567890abcdef...",
      "s": "0xfedcba0987654321..."
    },
    "authorization": {
      "owner": "0x...",
      "spender": "0x...",
      "value": "1000000",
      "deadline": "1740675689",
      "nonce": 5
    },
    "paymentNonce": "0xf374..."
  }
}

EIP-712 Domain

The permit signature uses EIP-712 typed data:

const domain = {
  name: "USD Coin",      // Token name
  version: "2",          // Token version
  chainId: 8453,         // Chain ID
  verifyingContract: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
};
 
const types = {
  Permit: [
    { name: "owner", type: "address" },
    { name: "spender", type: "address" },
    { name: "value", type: "uint256" },
    { name: "nonce", type: "uint256" },
    { name: "deadline", type: "uint256" }
  ]
};

The name and version fields in extra must match the token’s EIP-712 domain. These vary by token - USDC uses "USD Coin" and "2".

Supported Tokens

TokenEIP-2612Networks
USDCEthereum, Base, Arbitrum, Polygon
USDTNot supported (no permit)
DAIEthereum, Base, Arbitrum
⚠️

USDT does not support EIP-2612 Permit. For USDT payments, use the exact scheme instead.

Settlement

Settlement Request

After processing the request, the server sends the actual usage amount:

{
  "paymentPayload": "...",
  "paymentRequirements": {...},
  "settleAmount": "150000",
  "usageDetails": {
    "unitsConsumed": 1500,
    "unitPrice": "100",
    "unitType": "token",
    "startTime": 1740672000,
    "endTime": 1740675600
  }
}

Settlement Rules

  1. settleAmount must be ≤ maxAmount
  2. settleAmount must be ≥ minAmount (if specified)
  3. If settleAmount is 0, no transfer occurs (nonce still consumed)
  4. Facilitator transfers exactly settleAmount, not maxAmount

Settlement Response

{
  "success": true,
  "transactionHash": "0x...",
  "settledAmount": "150000",
  "maxAmount": "1000000",
  "blockNumber": 12345678,
  "gasUsed": "85000"
}

SDK Usage

import { UptoEvmScheme, UptoPaymentRequirements } from '@t402/evm';
 
// Client: Create payment
const scheme = UptoEvmScheme.client({
  signer: walletSigner,
  network: 'eip155:8453'
});
 
const payload = await scheme.createPaymentPayload(requirements);
 
// Server: Define requirements
const requirements: UptoPaymentRequirements = {
  scheme: 'upto',
  network: 'eip155:8453',
  maxAmount: '1000000',
  minAmount: '10000',
  asset: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
  payTo: '0x...',
  maxTimeoutSeconds: 300,
  extra: {
    unit: 'token',
    unitPrice: '100',
    name: 'USD Coin',
    version: '2'
  }
};
 
// Server: Settle with actual usage
const settlement = await facilitator.settle({
  payload,
  requirements,
  settleAmount: '150000',
  usageDetails: {
    unitsConsumed: 1500,
    unitPrice: '100',
    unitType: 'token'
  }
});

Security Considerations

Client Protection

  • Client only authorizes maximum exposure (maxAmount)
  • Actual charge determined by server’s settlement request
  • Monitor settlement amounts vs. expected usage
  • Set appropriate maxAmount limits

Server Accountability

  • Accurately report usage in settlement requests
  • Settlement amounts should be auditable
  • Log usageDetails for dispute resolution
  • Provide transparent pricing (unit/unitPrice)

Facilitator Role

  • Must not settle more than authorized maxAmount
  • Must verify settlement amount is within bounds
  • Provides settlement receipts with details
  • Maintains audit trail

Partial Settlement

If a request is interrupted mid-processing:

  1. Server calculates partial usage
  2. Server settles for partial amount
  3. Client receives partial response with settlement header

Example: Client authorizes $1.00, request generates 500 tokens before timeout, server settles for $0.05.

Comparison with Exact Scheme

Featureexactupto
Amount fieldamountmaxAmount
Settlement amountFixedVariable (≤ max)
Client riskKnown exactlyMaximum exposure
Server complexityLowerHigher (usage tracking)
EVM implementationEIP-3009EIP-2612 Permit
Best forFixed pricingUsage-based billing

Troubleshooting

Common Issues

“Permit signature invalid”

  • Check that name and version match the token’s EIP-712 domain
  • Verify the deadline hasn’t passed
  • Ensure nonce matches client’s current permit nonce

“Settlement amount exceeds maximum”

  • settleAmount must be ≤ maxAmount
  • Check for unit conversion errors

“Token does not support permit”

  • Use a token with EIP-2612 support (USDC, DAI)
  • For USDT, use exact scheme instead

Debug Logging

Enable debug logs to trace the payment flow:

// TypeScript
process.env.T402_DEBUG = 'true';
# Python
import logging
logging.getLogger('t402').setLevel(logging.DEBUG)

Further Reading