ByAUJay
Summary: A step-by-step playbook for shipping Web3‑native APIs that enterprises can actually run in production: robust wallet authentication (SIWE, AA passkeys, session keys), rate limits that survive bots and RPC ceilings, and onchain payments that cover subscriptions, streaming, and true pay‑per‑call with stablecoins.
Creating API for Web3: Authentication, Rate Limits, and Onchain Payments
Decision‑makers want Web3 benefits without Web3 headaches. This post compresses what we implement at 7Block Labs for clients building APIs consumed by wallets, agents, or dapps: how to authenticate users without passwords, how to rate‑limit fairly (and avoid blowing through your own RPC quotas), and how to charge onchain—recurring, streaming, or per call.
Below you’ll find concrete patterns, exact headers and message formats, emerging best practices, and integration notes you can paste into a spec or PR.
1) Authentication that fits Web3 (and Web2 SSO)
There are three production‑grade ways to prove “who” is calling your API:
- SIWE (Sign‑In with Ethereum) for off‑chain sessions using a wallet signature.
- Account Abstraction (AA, ERC‑4337) for passkeys and gasless onboarding.
- OIDC bridge (optional) to plug wallets into enterprise SSO.
1.1 SIWE: the baseline that works everywhere
SIWE is an EIP‑standardized, human‑readable message the user signs; your server verifies the signature and issues a session (cookie or JWT). The spec mandates fields including domain, chainId, nonce, and issuedAt. Nonce must be at least 8 alphanumeric chars; bind the session to both domain and chainId to resist replay. Add expirationTime for short‑lived assertions. (eips.ethereum.org)
Key server rules you should enforce immediately:
- Verify EOA signatures AND contract‑account signatures via ERC‑1271 so smart contract wallets can sign in too. (eips.ethereum.org)
- Match the SIWE “domain” to your HTTPS origin; reject cross‑origin tricks as the spec recommends. (eips.ethereum.org)
- Use EIP‑712 hashing libraries where possible; guarantees structured‑data signing correctness. (eips.ethereum.org)
Minimal backend flow (TypeScript with spruceid/siwe):
import { SiweMessage } from 'siwe'; import { verifyTypedDataSig, verifyERC1271 } from './sig-helpers'; // your helpers export async function siweLogin(req, res) { const { message, signature } = req.body; const siwe = new SiweMessage(message); // 1) Basic spec checks siwe.validate(message); // throws if malformed (version, chainId, etc.) // 2) Signature: try EOA, then ERC-1271 const addr = siwe.address.toLowerCase(); const okEOA = await verifyTypedDataSig(addr, siwe.prepareMessage(), signature); const ok1271 = okEOA ? true : await verifyERC1271(addr, siwe.prepareMessage(), signature); if (!ok1271) return res.status(401).end(); // 3) Nonce & replay checks await assertFreshNonce(req.sessionId, siwe.nonce); // 4) Bind to domain+chain if (siwe.domain !== new URL(process.env.PUBLIC_ORIGIN).host) return res.status(400).end(); // 5) Create session/JWT with address and plan entitlements const token = await issueJwt({ sub: addr, chainId: siwe.chainId, plan: 'pro' }); res.json({ token }); }
Useful libraries and docs: SIWE spec, EIP‑712, ERC‑1271, and Spruce’s implementations. (eips.ethereum.org)
Advanced: SIWE over OIDC. If you need SSO into existing SaaS or enterprise stacks, deploy Spruce’s SIWE OIDC provider (standalone or Cloudflare Worker) and federate via standard OIDC flows (Auth0/Okta/etc.). (docs.login.xyz)
1.2 AA wallets, passkeys, and session keys
AA (ERC‑4337) lets you offer passkey‑based, seed‑less onboarding and gasless UX. You’ll see “UserOperation” objects (not transactions) and “paymasters” to sponsor gas. For APIs, the impact is twofold:
- You can onboard non‑crypto users via passkeys (WebAuthn) and still tie their sessions to a wallet address.
- You can mint or verify “session keys” with narrow scopes and TTLs—great for high‑frequency API calls from untrusted clients (mobile, browser, agents). (eips.ethereum.org)
Vendor reality in 2025:
- Coinbase Smart Wallet: passkeys, ERC‑4337, paymaster for gas sponsorship; Base first‑class support. (coinbase.com)
- ZeroDev and similar SDKs: issue short‑lived session keys scoped to specific contract methods or API actions. (v3-docs.zerodev.app)
Tip: If you verify signatures on your API, support both EOA (ecrecover) and 1271 (contract wallets) for the signature field of requests. ERC‑4337 also has ongoing work for signature aggregation (ERC‑7766) which can reduce costs at scale. (eips.ethereum.org)
2) Rate limits that actually work for wallets, bots, and RPC ceilings
Classical IP‑based throttling won’t cut it when thousands of users sit behind a shared gateway or botnet. You need layered rate limits:
- Edge limits (protect your origin, block volumetric abuse early).
- Identity limits (per wallet address, per SIWE session, per NFT plan).
- Upstream limits (respect your RPC provider ceilings).
2.1 Standardize your limit headers and 429s
Return 429 Too Many Requests with Retry‑After. Publish limits using the emerging IETF “RateLimit” fields so SDKs can auto‑throttle. We recommend:
- On success:
,RateLimit-Policy
(or older trio:RateLimit
,RateLimit-Limit
,RateLimit-Remaining
).RateLimit-Reset - On throttle: also include
(seconds). (developer.mozilla.org)Retry-After
Example:
HTTP/1.1 200 OK RateLimit-Policy: "burst";q=120;w=60, "day";q=100000;w=86400 RateLimit: "burst";r=40;t=18, "day";r=82950;t=43200
Those headers communicate remaining quota (r) and reset time (t) per policy window; clients can adapt without guessing. Cloudflare and other platforms are adopting these patterns, and the drafts are widely referenced. (developers.cloudflare.com)
2.2 Identity‑aware limits
Choose at least one stable key:
- SIWE address (best default).
- Contract account address (1271) for teams/orgs.
- Token/NFT gate: e.g., subscription NFT (ERC‑5643) or Unlock membership; apply different per‑minute quotas to tiers. (eips.ethereum.org)
Practical: store counters keyed by
address:window, not by IP. Include the address and plan in your JWT so edge workers can enforce without a database roundtrip.
2.3 Don’t shock your RPC providers
Your API’s reliability also depends on your upstream Web3 infra—Infura, Cloudflare, Alchemy, etc.—which have hard throughput and daily credit caps. Examples:
- Infura “Core/Free” has daily credit caps and per‑second ceilings; exceeding limits returns 402/429 and even severs WebSockets until reset. (support.infura.io)
- Cloudflare Ethereum Gateway includes request quotas per plan; plan limits apply to gateway usage. (developers.cloudflare.com)
- Alchemy recommends keeping requests under 100 KB and responses under ~10 MB; batch constraints apply (e.g., max 20 per WS batch). (alchemy.com)
Mitigations we ship by default:
- Cache hot JSON‑RPC responses (latest block, ERC‑20 metadata) at the edge; prefer WebSockets for high‑fan‑out subscriptions, HTTP for bursty reads.
- Token‑bucket with jittered backoff on 429 or upstream
headers.RateLimit* - Concurrency caps per tenant to prevent “thundering herds” after resets.
3) Onchain payments: recurring, streaming, and true pay‑per‑call
“Pay me for this API call” is easy in Web2—cards + cents. Onchain, you want stability (USDC), predictable UX (low fees), and provability (settlement receipts you can reconcile). Here’s what’s working in production today.
3.1 Accept stablecoins with enterprise rails
- Stripe: “Pay with Crypto” supports USDC across Base, Ethereum, Solana, and Polygon, settles as fiat to your Stripe balance, and charges a clear 1.5% fee. Subscriptions with stablecoins are rolling out (private preview) with a wallet‑save smart contract that avoids re‑prompts each cycle. This is the fastest way to add onchain without new treasury ops. (docs.stripe.com)
- Coinbase Onchain Payment Protocol (Commerce): merchants were migrated to a new protocol in 2024; it auto‑settles to USDC (or USD for managed merchants) and supports low‑cost L2s like Base. For APIs, you get webhooks plus onchain receipts. (help.coinbase.com)
If you’re US‑centric and okay with a processor fee, Stripe/Coinbase give you dispute tooling, refunds, and dashboards. If you want purely onchain control, use the patterns below.
3.2 Onchain recurring subscriptions (two robust patterns)
-
Subscription NFTs (ERC‑5643): mint an expiring NFT; your backend allows access if
. The interface standardizes renew/cancel/expiry, and ENS uses a similar pattern operationally. Renewal can be automated by your agents or by users. (ercs.ethereum.org)expiresAt(tokenId) > now -
Unlock Protocol memberships: deploy a “Lock” (ERC‑721 membership with onchain expiration and renewal). Auto‑renew is handled via ERC‑20 approvals; there’s also fiat recurring support that extends keys onchain. You can change duration, set prices in USDC, and even burn time on transfers for secondary market policy. (docs.unlock-protocol.com)
When to choose which:
- Need a general subscription primitive with rich ecosystem tooling and dashboard? Unlock.
- Want a minimal, portable ERC‑721 interface you can control entirely? ERC‑5643.
3.3 Streaming (per‑second) payments that double as entitlements
Streams let you charge while value flows. If the stream drops to zero, you throttle or cut off API calls automatically.
- Superfluid: continuous token flows with “Super Tokens.” Read
to confirm active payment. Great for usage‑based pricing (“$0.001/sec while the job runs”). (docs.superfluid.org)getNetFlowRate - Sablier: mature lockup/flow primitives; each stream is an ERC‑721 (collateralizable), with flexible curve options (linear, cliffs, etc.). You can treat an active stream NFT as a “paid seat.” (sablier.com)
Implementation note: do onchain verification (flow > 0) server‑side, cache for 30–60s, and accept temporary lapses to avoid flapping.
3.4 Real pay‑per‑call with USDC and signatures (no user gas)
If you need exact “$0.001 per API hit” and don’t want the user to submit a transaction each time:
- EIP‑3009 “TransferWithAuthorization/ReceiveWithAuthorization” lets a user sign an EIP‑712 authorization off‑chain for USDC; your server (or relayer) submits a single onchain transaction to pull USDC with the user’s signature. You can aggregate N authorizations per batch to amortize gas. Prefer
to prevent front‑running. (eips.ethereum.org)receiveWithAuthorization
Concrete shape of a per‑call flow:
- Client includes a short‑lived EIP‑3009 authorization in the API request body (USDC amount for this call).
- Server validates signature and enqueues the authorization.
- Once batch size or time threshold is met (e.g., 200 calls or 30s), server posts one transaction calling
for each item.receiveWithAuthorization - If onchain settlement succeeds, mark calls as paid; otherwise, 402 Payment Required.
Caveats: ensure chain coverage (Polygon’s bridged USDC historically diverged on 3009 support—validate token contract features), and note Circle has proposed 1271‑compatible extensions for contract wallets. (web3-ethereum-defi.readthedocs.io)
3.5 Using “permit” for prepaid credits
If you prefer prepaid balances:
- Issue “API Credits” as an ERC‑20. User approves your billing contract with EIP‑2612 permit (gasless approval). Your contract burns credits per API receipt. Easy to reason about, audits well, and keeps all logic onchain. (eips.ethereum.org)
3.6 Attested entitlements (tamper‑evident off‑chain)
Store metering off‑chain but attest the plan/limits or settled usage onchain using EAS (Ethereum Attestation Service). Create a schema for “plan:pro, rpm:600, expires:timestamp”. Your API trusts your signer; customers can verify the attestation on EAS Scan. Clean, portable, and chain‑agnostic. (attest.org)
4) Reference architecture: glue it together
Here are three deployment‑proven blueprints you can choose from or mix.
4.1 SIWE + JWT + Stripe/Coinbase subscriptions (fastest enterprise path)
- Auth: SIWE login; server issues JWT bound to address+chainId; address stored in tenant record.
- Limits: per‑address token bucket at the edge; publish
headers; return 429+Retry‑After on overflow.RateLimit* - Payments: Stripe “Pay with Crypto” or Coinbase Commerce. Webhooks update entitlements in DB and (optionally) mint an EAS attestation for auditability. (docs.stripe.com)
Why: Enterprise‑friendly operations, minimal smart‑contract surface, quick to launch.
4.2 Unlock membership or ERC‑5643 subscription (pure onchain access)
- Auth: SIWE; on each request, your edge worker checks if the calling address holds a non‑expired membership NFT (Unlock) or an ERC‑5643 token with
.expiresAt > now - Limits: assign SKU tiers (Starter/Pro) via token ID or lock address; edge rates keyed by address.
- Payments: all onchain; users renew in wallet; your API reflects changes with a 1‑block delay. (docs.unlock-protocol.com)
Why: No web2 processor, global reach, transparent onchain entitlements.
4.3 USDC pay‑per‑call + batching (true micropayments)
- Auth: AA passkeys or SIWE for session; session carries public address.
- Payment: each API call carries a 3009 authorization for, say, 0.001 USDC; server batches N authorizations into a single
transaction every T seconds.receiveWithAuthorization - Limits: light pre‑limit + post‑settlement reconciliation; failed batches mark calls unpaid (return 402 on retry). (eips.ethereum.org)
Why: Precise metering for agentic/AI oracles or HPC endpoints; no pre‑funding or monthly cycles.
5) Practical implementation details you can copy
- Nonce management (SIWE): keep a 10‑minute TTL and one‑time use; store nonce in Redis keyed by session; reject reuse. The spec requires nonce >= 8 alphanumeric chars. (eips.ethereum.org)
- Contract signatures: when
is true, run ERC‑1271isContract(address)
with your EIP‑712 hash; cache positive results for 60s. (eips.ethereum.org)isValidSignature - Rate limiting headers: adopt the IETF draft naming; include both
and aRateLimit-Policy
item list with remaining (r) and reset (t). Always returnRateLimit
on 429. (ietf.org)Retry-After - RPC hygiene: cap concurrent JSON‑RPC calls per tenant and set request/response size targets well below your provider’s soft limits (e.g., keep requests under 100 KB). (alchemy.com)
- Streaming checks: cache Superfluid/Sablier state, but re‑verify on mutation events. Use a small grace window (e.g., 30s) before terminating access to avoid jitter. (docs.superfluid.org)
- Unlock auto‑renew: for ERC‑20‑priced locks, call
from a keeper whenrenewMembershipFor
is true; users pre‑approve an allowance. (docs.unlock-protocol.com)isRenewable - EIP‑3009 batching: use
inside your billing contract to atomically settle a batch; never rely onreceiveWithAuthorization
from another contract because of mempool replay risk. (eips.ethereum.org)transferWithAuthorization - Attestations: define a compact EAS schema and publish it; your verifier checks “issuer == your signer” and “expiration > now.” (github.com)
6) Compliance signals for U.S. businesses (non‑legal)
If you receive, custody, or transmit customer funds, map your model to U.S. expectations:
- OFAC: maintain sanctions screening commensurate with risk; guidance for the virtual currency industry highlights IP geofencing, address screening, and training/testing programs. (ofac.treasury.gov)
- FinCEN: most non‑custodial API providers aren’t money transmitters; but if you intermediate customer funds, review 2019 CVC guidance on when MSB rules can apply. (fincen.gov)
Stripe/Coinbase processors help by absorbing parts of this surface; purely onchain models should still implement reasonable screening and disclosures.
7) What to ship this quarter (a clean checklist)
- Auth
- Implement SIWE with ERC‑1271 support and 10‑minute nonce TTL.
- Optionally enable AA passkeys via Coinbase Smart Wallet or ZeroDev for new‑to‑crypto users. (docs.cdp.coinbase.com)
- Limits
- Edge‑enforce token buckets keyed by wallet address; publish
headers andRateLimit*
. (ietf.org)Retry-After - Constrain upstream RPC concurrency per tenant to 70–80% of your plan ceilings. (support.infura.io)
- Edge‑enforce token buckets keyed by wallet address; publish
- Payments (pick one to start)
- Stripe/Coinbase for USDC subscriptions. (docs.stripe.com)
- Unlock/5643 for onchain memberships. (docs.unlock-protocol.com)
- EIP‑3009 for per‑call; batch to keep gas <$0.01/call on Base. (eips.ethereum.org)
- Auditability
- Emit EAS attestations for plan/limits snapshots. (attest.org)
8) Emerging practices to watch
- ERC‑4337 signature aggregation (ERC‑7766) to reduce validation overhead for multi‑user batches. (eips.ethereum.org)
- EIP‑712 evolutions like EIP‑7713 (“box” type) for nested typed‑data—useful if you embed rich payment authorizations in a single message. (eips.ethereum.org)
- Contract‑wallet‑friendly 3009 extensions (1271 validation) landing in production tokens. (ethereum-magicians.org)
9) A concrete, end‑to‑end example (put it in your spec)
- Login: SIWE v1, domain‑bound to
, chainId 8453 (Base).api.example.com - Session: JWT with
,sub=<address>
,plan
,rpm
.exp=24h - Limits: Edge Worker reads JWT, enforces
via token bucket; returns:rpmRateLimit-Policy: "rpm";q=600;w=60RateLimit: "rpm";r=120;t=12
- Payment: Unlock membership on Base priced in USDC (ERC‑20). Auto‑renew enabled via
; server cachesrenewMembershipFor
for 30s. (docs.unlock-protocol.com)keyExpirationTimestampFor(address) - RPC: All reads via Cloudflare Gateway, with a shared cache for
and metadata; per‑tenant concurrency cap set to 15 req/s (well under plan limits). (developers.cloudflare.com)eth_blockNumber
Result: passwordless auth, predictable limits, and an onchain subscription that any auditor (or customer) can verify independently.
How we help
7Block Labs designs and ships these patterns for startups and enterprises: we implement SIWE/AA auth, edge‑rate‑limit stacks, and billing (Stripe/Coinbase, Unlock, Superfluid/Sablier, or EIP‑3009) with the observability, alerts, and compliance signals your stakeholders expect. If you want a reference implementation on Base with passkeys and USDC, we can deliver it in weeks—not quarters.
References (selected):
- SIWE (EIP‑4361), EIP‑712, ERC‑1271. (eips.ethereum.org)
- ERC‑4337 AA, session keys/providers, passkeys (Coinbase). (eips.ethereum.org)
- Rate‑limit headers (IETF drafts) and 429 semantics. (ietf.org)
- RPC limits and best practices (Infura, Cloudflare, Alchemy). (support.infura.io)
- Payments: Stripe crypto docs and subscriptions preview; Coinbase Onchain Payment Protocol/Commerce. (docs.stripe.com)
- Subscriptions/streaming: ERC‑5643, Unlock, Superfluid, Sablier. (ercs.ethereum.org)
- EIP‑3009 pay‑per‑call and caveats. (eips.ethereum.org)
- Attestations: EAS (attest.org). (attest.org)
If you want a deeper dive or a code‑complete starter, ping us—this is what we do.
Like what you're reading? Let's build together.
Get a free 30‑minute consultation with our engineering team.

