Introduction
What is Drip?
Drip is an on-chain metered billing platform built on Base using USDC. It enables businesses to charge customers for usage-based services with minimal trust assumptions and full transparency.
- On-chain settlement: All charges are recorded on Base for full auditability
- USDC payments: Stable, predictable pricing without crypto volatility
- User-controlled funds: Customers hold their own funds via smart accounts
- API-first: Simple REST API for recording usage and triggering charges
How It Works
Off-chain Metering
Your application records usage events via the Drip API. Events are stored off-chain for fast processing.
Usage Pricing
Usage is priced according to your pricing plans. Charges are calculated automatically.
On-chain Settlement
Charges are settled on-chain via session keys. Transactions are batched for gas efficiency.
Getting Started
Quick Start Guide
1. Create a Business Account
Sign up for Drip and create your business profile in the dashboard.
2. Get Your API Key
Navigate to API Keys and generate a new key. Store it securely.
# Your API key looks like this:
sk_live_a1b2c3d4e5f6g7h8i9j0...3. Create a Customer
curl -X POST https://api.drip.dev/v1/customers \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"externalCustomerId": "user_123",
"onchainAddress": "0x742d35Cc6634C0532925a3b844Bc9e7595f..."
}'4. Record Usage & Charge
curl -X POST https://api.drip.dev/v1/usage \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"customerId": "cus_abc123",
"usageType": "api_call",
"quantity": 100,
"idempotencyKey": "unique-request-id"
}'Core Concepts
Smart Accounts
Drip uses ERC-4337 smart accounts (DripAccount) for customer fund management. Unlike traditional custodial solutions, users maintain control of their own funds.
- Users deposit USDC into their own smart account
- Funds remain in the user's control until charged
- Account abstraction enables gasless transactions for users
- Compatible with existing EOA wallets via counterfactual deployment
Session Keys
Session keys provide scoped, time-limited permissions for billing operations. They allow Drip to charge customers without requiring user signatures for each transaction.
- Target scoping: Keys can only call specific contract addresses
- Selector scoping: Keys are limited to specific function selectors
- Time bounds: Keys expire after a configurable duration (e.g., 30 days)
- Rate limits: maxPerCall and maxPerPeriod caps prevent excessive charges
- Revocable: Users can revoke session keys at any time
BillingModule
The BillingModule smart contract handles USDC custody and charge execution. It enforces all billing invariants on-chain.
- Deposits: Users deposit USDC into their billing balance
- Withdrawals: Users can withdraw available balance at any time
- Charges: Authorized charges deduct from user balance
- Events: All operations emit events for auditability
Replay Protection
Every usage event generates a unique usageId that prevents double-charging. This is enforced both off-chain and on-chain.
- Each charge transaction includes the usageId
- The BillingModule rejects duplicate usageIds
- Use
idempotencyKeyfor client-side deduplication - Charges can be queried and reconciled by usageId
Depeg Protection
Drip includes a circuit breaker that pauses billing operations if USDC depegs significantly from its $1 target. This protects both merchants and customers from unexpected value loss.
- 5% threshold: Billing pauses if USDC/USD price deviates more than 5%
- Chainlink oracle: Price feeds from decentralized oracles
- Automatic resume: Operations resume when price stabilizes
- Manual override: Operators can pause/unpause if needed
Integration Guide
Authentication
All API requests require authentication via Bearer token. Include your API key in the Authorization header.
curl -X GET https://api.drip.dev/v1/customers \
-H "Authorization: Bearer sk_live_your_api_key_here"Security tip: Never expose API keys in client-side code. Make API calls from your backend server only.
Creating Customers
Before charging a user, create a customer record linking their identity to their on-chain address.
interface CreateCustomerRequest {
externalCustomerId?: string; // Your internal user ID
onchainAddress: string; // 0x... Ethereum address
metadata?: Record<string, any>;
}
// Example
const customer = await fetch('/v1/customers', {
method: 'POST',
headers: {
'Authorization': 'Bearer sk_live_...',
'Content-Type': 'application/json'
},
body: JSON.stringify({
externalCustomerId: 'user_123',
onchainAddress: '0x742d35Cc6634C0532925a3b844Bc9e7595f...',
metadata: { plan: 'pro', signupDate: '2024-01-15' }
})
});Recording Usage Events
Record usage events as they occur. Each event triggers a charge based on your pricing configuration.
interface RecordUsageRequest {
customerId: string; // Drip customer ID
usageType: string; // e.g., "api_call", "compute_minute"
quantity: number; // Must be positive
idempotencyKey?: string; // Client-generated, max 64 chars
metadata?: Record<string, any>;
}
// Synchronous charging (waits for on-chain confirmation)
const result = await fetch('/v1/usage', {
method: 'POST',
headers: { 'Authorization': 'Bearer sk_live_...', 'Content-Type': 'application/json' },
body: JSON.stringify({
customerId: 'cus_abc123',
usageType: 'api_call',
quantity: 100,
idempotencyKey: 'req_' + Date.now()
})
});
// Async charging (returns immediately, use webhooks for confirmation)
const asyncResult = await fetch('/v1/usage/async', {
method: 'POST',
// ... same body
});Handling Webhooks
Subscribe to webhooks for real-time notifications about charges, balances, and other events.
// Register a webhook
await fetch('/v1/webhooks', {
method: 'POST',
headers: { 'Authorization': 'Bearer sk_live_...', 'Content-Type': 'application/json' },
body: JSON.stringify({
url: 'https://your-app.com/webhooks/drip',
events: ['charge.succeeded', 'charge.failed', 'customer.balance.low']
})
});
// Verify webhook signature (HMAC-SHA256)
const crypto = require('crypto');
const signature = req.headers['x-drip-signature'];
const expectedSig = crypto
.createHmac('sha256', webhookSecret)
.update(JSON.stringify(req.body))
.digest('hex');
const isValid = crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expectedSig)
);Error Handling
The API returns standard HTTP status codes and structured error responses.
| Status | Code | Description |
|---|---|---|
| 401 | UNAUTHORIZED | Invalid or missing API key |
| 402 | PAYMENT_REQUIRED | Insufficient customer balance |
| 403 | ACCOUNT_PAUSED | Account paused due to low balance |
| 404 | NOT_FOUND | Resource not found |
| 409 | DUPLICATE_CUSTOMER | Customer already exists |
| 422 | VALIDATION_ERROR | Invalid request parameters |
| 429 | RATE_LIMIT_EXCEEDED | Usage cap or rate limit exceeded |
Security Model
Trust-Minimized Architecture
Drip is designed to minimize trust requirements. Users maintain control of their funds at all times, and billing operations are constrained by on-chain logic.
User Controls
- Users own their smart account
- Users approve session key permissions
- Users can revoke keys at any time
- Users can withdraw funds at any time
On-chain Guarantees
- Session key limits enforced by contract
- Duplicate charges rejected on-chain
- Balance checks prevent overdrafts
- All operations emit verifiable events
Rate Limits & Caps
Multiple layers of rate limiting protect against runaway charges.
| Limit Type | Scope | Description |
|---|---|---|
| maxPerCall | Session Key | Maximum USDC per individual charge |
| maxPerPeriod | Session Key | Maximum USDC per rolling time window |
| DAILY_CHARGE_LIMIT | Customer | Maximum charges per day per customer |
| SINGLE_CHARGE_LIMIT | Customer | Maximum amount for a single charge |
Security Best Practices
- Store API keys in environment variables, never in code
- Use separate API keys for development and production
- Rotate API keys periodically
- Always verify webhook signatures before processing
- Implement usage caps appropriate for your use case
- Monitor the balance.low webhook to alert customers before charges fail
- Use idempotencyKey for all usage recording to prevent duplicates
x402 Payment Protocol
What is x402?
x402 is a protocol for HTTP 402 Payment Required responses that enables micropayments for API access. When a client receives a 402 response, it can automatically handle payment and retry the request - perfect for AI agents and automated clients.
How x402 Works
Client Calls API
Client makes a normal API request to a protected endpoint.
Server Returns 402
If payment is required, server responds with 402 and X-Payment-* headers.
Client Signs Payment
Client uses a session key to sign the payment request via /v1/x402/sign.
Client Retries with Proof
Client retries the original request with X-Payment-* proof headers.
Server Verifies & Processes
Server verifies the payment signature and processes the request.
Response Headers (402)
When a 402 Payment Required is returned, these headers contain payment details:
HTTP/1.1 402 Payment Required
X-Payment-Required: true
X-Payment-Amount: 0.001000
X-Payment-Currency: USDC
X-Payment-Recipient: 0x742d35Cc6634C0532925a3b844Bc9e7595f...
X-Payment-Chain: base-sepolia
X-Payment-Description: Usage charge: api_call
X-Payment-Usage-Id: 550e8400-e29b-41d4-a716-446655440000
X-Payment-Expires: 1703001234567Payment Proof Headers
After signing, include these headers when retrying the request:
POST /v1/usage HTTP/1.1
Authorization: Bearer sk_live_...
X-Payment-Signature: 0x1234...abcd
X-Payment-Session-Key: sk_session_123
X-Payment-Smart-Account: 0x742d35Cc6634C0532925a3b844Bc9e7595f...
X-Payment-Timestamp: 1703001234567Signing Endpoint
Use the signing endpoint to create a payment signature:
// POST /v1/x402/sign
const response = await fetch('/v1/x402/sign', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
smartAccount: '0x742d35Cc6634C0532925a3b844Bc9e7595f...',
sessionKeyId: 'sk_session_123',
paymentRequest: {
amount: '0.001000',
recipient: '0x...',
usageId: '550e8400-e29b-41d4-a716-446655440000',
expiresAt: 1703001234567
}
})
});
const { signature, timestamp } = await response.json();Use Cases
- AI Agents: Autonomous agents can pay for API access without human intervention
- Automated Clients: Scripts and bots can handle payment flows programmatically
- Micropayments: Pay per request without subscription commitments
- Multi-tenant Apps: Different users with different session key permissions
FAQ
What chains does Drip support?
Drip is deployed on Base L2 (mainnet) and Base Sepolia (testnet). Base provides low transaction fees and fast confirmation times, making it ideal for metered billing.
What happens if a user runs out of funds?
When a user's balance is too low for a charge, the API returns a 402 Payment Required error. You can subscribe to the customer.balance.low webhook to proactively notify users before this happens.
How are gas fees handled?
Users pay gas fees for deposits and withdrawals. For charges, Drip batches transactions and covers gas fees, passing a small portion to merchants as part of the settlement fee.
Can users revoke session keys?
Yes. Users can revoke session keys at any time through the dashboard or by calling the smart contract directly. Revoked keys immediately lose the ability to authorize charges.
Is there a minimum charge amount?
There is no minimum charge amount enforced by Drip. However, for very small charges, batching is recommended to optimize gas efficiency.
