Pay with AI3 & USDC — Developer Integration
This page covers how to integrate permissionless Auto Drive credit purchasing into your own application using the credits API and one of two payment methods:
| Payment method | Asset | Network | Contract |
|---|---|---|---|
AI3 (ai3_native) | Native AI3 | Autonomys Auto-EVM (Chain ID 870) | AutoDriveCreditsReceiver |
USDC (usdc_eth) | USDC (ERC-20) | Ethereum mainnet (Chain ID 1) | AutoDriveUSDCReceiver |
Both methods use the same payment intent model and the same credits, limits, and expiry. The AI3 flow is described first; the differences for USDC are covered in Pay with USDC.
For the end-user purchase walkthroughs, see the Pay with AI3 guide and the Pay with USDC guide.
For a complete working example of Pay with AI3 in a real application, see Eulonomys — a reference app with full source code showing the payment intent flow, on-chain contract calls, and Auto Drive uploads end-to-end.
How It Works
The payment system is built around a payment intent model. An AI3 purchase follows these steps:
- (Optional) Your app fetches the current storage price (
GET /intents/price) to show an estimate. The price reflects the live protocol-level DSN storage cost, read from the Autonomys consensus chain, plus a service fee. - Your app asks the Auto Drive backend to create a payment intent (
POST /intents) — a server-side record that locks the price per byte (shannonsPerByte) and binds abytes32intent ID to the authenticated account for 10 minutes. - Your app calls
payIntent(intentId)on theAutoDriveCreditsReceivercontract on Auto-EVM, sendingshannonsPerByte × bytesAI3 asmsg.value. - Your app submits the transaction hash to the watch endpoint (
POST /intents/:id/watch); the backend waits for 6 block confirmations and then grants the credits. - Your app polls the intent (
GET /intents/:id) until it reaches a terminal status.
Credits are granted as paymentAmount ÷ shannonsPerByte bytes (rounded down). They are available immediately after confirmation and can be used via the dashboard, the Auto SDK, or the REST API.
Smart Contracts
| Contract | Payment method | Network | Chain ID | Address |
|---|---|---|---|---|
AutoDriveCreditsReceiver | AI3 | Autonomys Auto-EVM | 870 | 0xBa5bed8325183c0807EcBC80C82D40Dc7Ac5cbf7 |
AutoDriveUSDCReceiver | USDC | Ethereum mainnet | 1 | 0x9c508Fa594f52032D574137585DD2F8A48F92261 |
The AI3 contract is described below. For the USDC contract, see Smart Contract (USDC).
AutoDriveCreditsReceiver (AI3)
| Field | Value |
|---|---|
| Network | Autonomys Auto-EVM |
| Chain ID | 870 |
| Address | 0xBa5bed8325183c0807EcBC80C82D40Dc7Ac5cbf7 |
View on Blockscout: AutoDriveCreditsReceiver
The chain ID, address, and payIntent ABI are also served by GET /intents/contract.
payIntent
function payIntent(bytes32 intentId) public payable whenNotPaused;intentId is the id returned by POST /intents. Send shannonsPerByte × bytes as msg.value. The contract accepts any non-zero amount and does not check it against the quote: the backend grants credits in proportion to what was actually paid, so paying less buys less storage.
The call reverts with InvalidAmount(0) when msg.value is zero, and with EnforcedPause() when the protocol team has paused payments in the event of a critical issue.
Event
event IntentPaymentReceived(bytes32 indexed intentId, uint256 paymentAmount);Emitted on successful payment. The backend reads this event from the transaction receipt to confirm the payment.
Payment Intent State Machine
PENDING ──► CONFIRMED ──► COMPLETED
│ │
│ ├──► OVER_CAP (account's 100 GB purchased credit limit exceeded)
│ │
│ └──► FAILED (payment could not be converted to credits, e.g. too small to buy one byte)
│
└──► EXPIRED (no payment received before the price lock ended)The API returns statuses in lowercase (pending, confirmed, completed, expired, failed, over_cap). The SDK converts them to uppercase.
Always create a fresh intent immediately before paying. Prices reflect live protocol storage cost and can change between requests.
API Reference
Base URL (mainnet): https://mainnet.auto-drive.autonomys.xyz/api
Authentication: endpoints marked as authenticated need both headers below. The API key must belong to a Google-authenticated account.
Authorization: Bearer <your-api-key>
X-Auth-Provider: apikeyGet the Storage Price
GET /intents/priceReturns the current price. No authentication required.
Example response:
{
"price": 4273583470658,
"pricePerGB": 4588.73,
"usd": {
"usdPerAi3": 0.00139,
"pricePerGBUsd": 6.39,
"asOf": "2026-10-07T18:08:26.587Z",
"lastTradeAt": "2026-10-06T01:38:35.000Z",
"stale": false
},
"usdUnavailableReason": null
}| Field | Description |
|---|---|
price | Price per byte, in Shannons (1 AI3 = 10^18 Shannons) |
pricePerGB | Price per GiB (1,073,741,824 bytes), in AI3 |
usd | USD estimate, or null when no AI3/USD rate is available. For display only — never use it to settle a payment |
usdUnavailableReason | Why usd is null; null when usd is present |
Get the Contract Info
GET /intents/contractReturns the Auto-EVM chain ID, the AutoDriveCreditsReceiver address, and the minimal payIntent ABI. No authentication required.
Example response:
{
"chainId": 870,
"contractAddress": "0xBa5bed8325183c0807EcBC80C82D40Dc7Ac5cbf7",
"payIntentAbi": [
{
"inputs": [{ "name": "intentId", "type": "bytes32" }],
"name": "payIntent",
"outputs": [],
"stateMutability": "payable",
"type": "function"
}
]
}Create a Payment Intent
POST /intentsLocks the current price per byte for the authenticated account for 10 minutes and returns the intent. Authenticated.
Request body (optional for AI3):
{
"requestedBytes": "10737418240"
}| Field | Description |
|---|---|
requestedBytes | Optional for AI3. Size of the purchase as a decimal string. When sent, Auto Drive checks it against the per-account cap and rejects an over-cap purchase before anything is paid |
paymentMethod | ai3_native (default) or usdc_eth. See Pay with USDC |
Response:
{
"id": "0xabc123...",
"userPublicId": "user-public-id",
"status": "pending",
"paymentMethod": "ai3_native",
"shannonsPerByte": "4273583470658",
"expiresAt": "2026-10-07T12:10:00.000Z"
}The response does not include a total amount. Compute it yourself: msg.value = shannonsPerByte × bytes. Pass id as the intentId argument to payIntent.
Errors:
| Status | Code | Meaning |
|---|---|---|
400 | — | requestedBytes is invalid or larger than the whole credit cap, or paymentMethod is not recognised |
401 | - | Authorization was sent without a usable X-Auth-Provider, or the API key was rejected |
403 | CREDIT_CAP_EXCEEDED | The purchase would exceed the per-account cap (only when requestedBytes is sent) |
404 | - | No credentials were sent, or the account cannot buy credits (for example, it is not Google-authenticated). The body is plain text Not Found, not JSON |
500 | - | The storage price could not be read, or another server error. Retry later |
503 | - | The storage price resolved to zero, or the authentication service is unavailable. Retry later |
Get an Intent
GET /intents/:idReturns the intent, including its status. Authenticated. Only the owner of the intent can read it (403 otherwise). Returns 410 once the price lock has lapsed on an intent that has no recorded transaction hash; see Polling after the Price Lock.
Confirm a Transaction
POST /intents/:id/watchSubmits the on-chain transaction hash. Authenticated. The backend waits for 6 confirmations before crediting the account.
Request body:
{
"txHash": "0xdef456..."
}txHash must be a 0x-prefixed 32-byte hex hash. Returns 204 No Content on success, 400 for a missing or malformed hash, and 410 if the intent has expired.
Integration Patterns
Pattern 1 — App-managed credits
Your application holds a funded Auto-EVM wallet and purchases credits on behalf of users. Useful for apps that abstract storage costs away entirely. The SDK makes the Auto Drive API calls; your wallet library sends the transaction.
import { createAutoDriveApi } from '@autonomys/auto-drive'
import { NetworkId } from '@autonomys/auto-utils'
import { ethers } from 'ethers'
const api = createAutoDriveApi({
apiKey: process.env.AUTO_DRIVE_API_KEY!,
network: NetworkId.MAINNET,
})
async function purchaseCredits(signer: ethers.Signer, sizeBytes: number) {
// 1. Create intent — price locked for 10 minutes.
// The SDK computes ai3AmountWei = shannonsPerByte × sizeBytes for you.
const intent = await api.createPaymentIntent(sizeBytes, { checkCreditCap: true })
// 2. Call payIntent on Auto-EVM, sending the computed amount
const { payIntentAbi } = await api.getPaymentContractInfo()
const contract = new ethers.Contract(intent.contractAddress, payIntentAbi as ethers.InterfaceAbi, signer)
const tx = await contract.payIntent(intent.intentId, { value: BigInt(intent.ai3AmountWei) })
await tx.wait()
// 3. Submit tx hash — backend waits for 6 confirmations, then grants credits
await api.watchPaymentTransaction(intent.intentId, tx.hash)
// 4. Wait for the intent to reach a terminal status
const status = await api.waitForPaymentCompletion(intent.intentId)
return { txHash: tx.hash, status } // 'COMPLETED' | 'EXPIRED' | 'FAILED' | 'OVER_CAP'
}If you call the REST API directly instead of using the SDK, send the authentication headers on POST /intents, GET /intents/:id, and POST /intents/:id/watch.
Pattern 2 — User-managed credits
Direct users to the Auto Drive dashboard to purchase credits themselves using the Pay with AI3 guide or the Pay with USDC guide. Your application uses the AutoSDK with the user’s API key — no on-chain interaction required in your code.
This is the lower-complexity option and is suitable for most applications.
Checking the Credit Cap Before Payment (SDK)
By default, api.createPaymentIntent(sizeBytes) does not send the purchase size to Auto Drive. Pass { checkCreditCap: true } to send it as requestedBytes. Auto Drive then rejects a purchase that would exceed the per-account cap before anything is paid, instead of the intent ending as OVER_CAP after an on-chain payment.
import { PaymentApiError } from '@autonomys/auto-drive'
try {
const intent = await api.createPaymentIntent(sizeBytes, { checkCreditCap: true })
} catch (error) {
if (
error instanceof PaymentApiError &&
(error.code === 'CREDIT_CAP_EXCEEDED' || error.status === 400)
) {
// Nothing was paid. Try a smaller size.
}
}A purchase that does not fit in the remaining headroom fails with CREDIT_CAP_EXCEEDED (403). A single purchase larger than the whole cap fails with HTTP 400 and no code. See Handling Errors for all PaymentApiError codes.
Pay with USDC
Credits can also be purchased with USDC on Ethereum mainnet. The intent model is the same as for AI3, with three differences:
- The intent is created with
paymentMethod: "usdc_eth"and an explicitrequestedBytes. The backend returns the exact USDC amount to pay asquotedTokenAmount, locked for 10 minutes. - USDC is an ERC-20 token, so the payer first approves the
AutoDriveUSDCReceivercontract and then callspayIntentWithToken(intentId, amount). There is nomsg.value. - The payment is made on Ethereum mainnet, not on Auto-EVM. The chain, receiver address, and token address are served by the API at
GET /payments/usdc/target— always read them from there (the SDK does this for you) rather than hardcoding them.
How It Works
With the SDK, steps 1 and 2 are a single call to api.createUsdcPaymentIntent(sizeBytes).
- Your app fetches the payment target (
GET /payments/usdc/target): chain ID, receiver address, USDC token address, token decimals, and the number of confirmations the backend waits for. - Your app creates a USDC payment intent (
POST /intentswithpaymentMethod: "usdc_eth"andrequestedBytes). The backend converts the AI3 storage cost to USDC at the current AI3/USD rate, adds a small quote margin, and returnsquotedTokenAmount(USDC base units, 6 decimals). - The payer calls
approve(receiverAddress, quotedTokenAmount)on the USDC token contract, thenpayIntentWithToken(intentId, quotedTokenAmount)onAutoDriveUSDCReceiver. - Your app submits the payment transaction hash to the watch endpoint; the backend waits for the required Ethereum confirmations (currently 6) and then grants the credits.
Credits are granted in proportion to the USDC actually received. Paying exactly quotedTokenAmount grants exactly requestedBytes.
Smart Contract (USDC)
| Field | Value |
|---|---|
| Contract | AutoDriveUSDCReceiver |
| Network | Ethereum mainnet |
| Chain ID | 1 |
| Address | 0x9c508Fa594f52032D574137585DD2F8A48F92261 |
| Accepted token | USDC — 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 |
View on Etherscan: AutoDriveUSDCReceiver
The same values are served by GET /payments/usdc/target. In code, read them from there (the SDK does this for you) rather than hardcoding them.
payIntentWithToken
function payIntentWithToken(bytes32 intentId, uint256 amount) external nonReentrant whenNotPaused;intentId is the id returned by POST /intents. amount is the USDC amount in base units (USDC has 6 decimals) — pass quotedTokenAmount exactly. The caller must have approved the receiver for at least amount beforehand; the contract pulls the tokens with transferFrom.
The whenNotPaused modifier allows the protocol team to pause payments in the event of a critical issue.
Event
event IntentTokenPaymentReceived(
bytes32 indexed intentId,
address token,
uint256 amount,
address indexed payer
);Emitted on successful payment. amount is the amount actually received by the contract, and payer is the account whose USDC allowance funded the payment.
On-chain errors
| Error | Description |
|---|---|
InvalidAmount(uint256) | amount is zero, or nothing was received |
EnforcedPause() | Contract is paused by the owner |
| ERC-20 allowance / balance errors | The payer did not approve enough USDC, or does not hold enough USDC |
API Reference (USDC)
Get the Payment Target
GET /payments/usdc/targetReturns where to send a USDC payment. Authenticated (see API Reference for the headers). Returns 403 USDC_PAYMENTS_DISABLED when USDC is not available on this deployment.
Example response:
{
"chainId": 1,
"receiverAddress": "0x9c508Fa594f52032D574137585DD2F8A48F92261",
"tokenAddress": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
"tokenDecimals": 6,
"confirmations": 6,
"settleGraceMs": 120000
}Create a USDC Payment Intent
POST /intentsAuthenticated (see API Reference for the headers).
Request body:
{
"paymentMethod": "usdc_eth",
"requestedBytes": "10737418240"
}requestedBytes is required for USDC intents (decimal string). It is also checked against the 100 GB per-account cap before the intent is created.
Response:
{
"id": "0xabc123...",
"userPublicId": "user-public-id",
"status": "pending",
"paymentMethod": "usdc_eth",
"shannonsPerByte": "4273583470658",
"quotedTokenAmount": "67071093",
"quotedAi3Shannons": "45887253108005714001920",
"usdRateAtCreation": "1392047389045704",
"expiresAt": "2026-10-07T12:10:00.000Z"
}Pass id as the intentId argument and quotedTokenAmount as the amount argument of payIntentWithToken. In this example, 67071093 base units = 67.071093 USDC for 10 GiB (about 45,887 AI3 at 0.00139 USD per AI3, plus the quote margin). usdRateAtCreation is the raw AI3/USD rate scaled by 10^18, without the margin, and is for reporting only.
USDC-specific errors:
| Status | Code | Meaning |
|---|---|---|
400 | — | requestedBytes missing or invalid (including larger than the whole credit cap), or paymentMethod not recognised |
403 | USDC_PAYMENTS_DISABLED | USDC is not available to this account or deployment — pay with AI3 |
403 | CREDIT_CAP_EXCEEDED | The purchase would exceed the 100 GB per-account cap — buy less |
503 | USDC_PAYMENTS_UNAVAILABLE | USDC is closed for now — pay with AI3, or retry later |
503 | PRICE_ORACLE_UNAVAILABLE / PRICE_UNSTABLE | No reliable AI3/USD rate right now — retry unchanged |
Confirm a Transaction
Same endpoint as for AI3: POST /intents/:id/watch with the payIntentWithToken transaction hash (not the approval hash). If the price lock has already lapsed, this call can return 410. The payment can still be credited from the on-chain event, so continue to wait for completion.
SDK Functions (USDC)
Requires
@autonomys/auto-drivev1.6.16 or later. Earlier versions do not include the USDC functions and exports listed below.
@autonomys/auto-drive wraps the USDC endpoints. As with AI3, the SDK does not sign anything: it returns the quote and where to pay, plus typed ABIs, and your wallet library sends the transactions.
| Function / export | Description |
|---|---|
api.getUsdcPaymentTarget() | Returns the UsdcPaymentTarget (chain ID, receiver, token, decimals, confirmations, settleGraceMs) |
api.createUsdcPaymentIntent(sizeBytes) | Creates a price-locked USDC intent for sizeBytes (number or bigint). Fetches the target for you and returns a UsdcPaymentIntent |
api.watchPaymentTransaction(intentId, txHash) | Same as for AI3 — pass the payIntentWithToken hash |
api.waitForPaymentCompletion(intentId, { settleGraceMs }) | Same as for AI3 — pass intent.settleGraceMs so a 410 after the lock lapses does not end the wait early |
erc20ApprovalAbi | Minimal ERC-20 ABI: approve, allowance, balanceOf |
usdcReceiverAbi | Minimal ABI for payIntentWithToken(bytes32, uint256) |
PaymentApiError | Error thrown on non-OK payment responses, with status and code |
See Available Functions for the full type definitions.
Integration Example (USDC)
The example below uses an Auto Drive API key and a funded Ethereum wallet (USDC for the payment, ETH for gas). All Auto Drive calls need the API key, so run this on your server.
import {
createAutoDriveApi,
erc20ApprovalAbi,
PaymentApiError,
usdcReceiverAbi,
} from '@autonomys/auto-drive'
import { NetworkId } from '@autonomys/auto-utils'
import { createPublicClient, createWalletClient, http, type Hex } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { mainnet } from 'viem/chains'
async function purchaseCreditsWithUsdc(sizeBytes: bigint) {
const api = createAutoDriveApi({
apiKey: process.env.AUTO_DRIVE_API_KEY!,
network: NetworkId.MAINNET,
})
// 1. Lock a USDC price. The SDK also fetches where to pay — never hardcode it.
const intent = await api.createUsdcPaymentIntent(sizeBytes)
// intent.usdcAmount — exact amount in base units (6 decimals)
// intent.usdcAmountFormatted — human-readable amount, e.g. "27.498"
// intent.chainId, intent.tokenAddress, intent.receiverAddress — where to pay
if (intent.chainId !== mainnet.id) throw new Error(`Unexpected USDC chain ${intent.chainId}`)
const account = privateKeyToAccount(process.env.PAYER_PRIVATE_KEY as Hex)
const transport = http(process.env.ETH_RPC_URL)
const publicClient = createPublicClient({ chain: mainnet, transport })
const walletClient = createWalletClient({ account, chain: mainnet, transport })
const amount = BigInt(intent.usdcAmount)
const token = intent.tokenAddress as Hex
const receiver = intent.receiverAddress as Hex
// 2. Approve the receiver to pull the USDC (skip if the allowance is enough)
const allowance = await publicClient.readContract({
address: token,
abi: erc20ApprovalAbi,
functionName: 'allowance',
args: [account.address, receiver],
})
if (allowance < amount) {
const approveHash = await walletClient.writeContract({
address: token,
abi: erc20ApprovalAbi,
functionName: 'approve',
args: [receiver, amount],
})
await publicClient.waitForTransactionReceipt({ hash: approveHash })
}
// 3. Pay the intent. No value: the receiver pulls the approved USDC.
// Wait for the receipt first, so block time does not use up the 410 grace.
const txHash = await walletClient.writeContract({
address: receiver,
abi: usdcReceiverAbi,
functionName: 'payIntentWithToken',
args: [intent.intentId as Hex, amount],
})
const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash })
if (receipt.status !== 'success') throw new Error(`USDC payment reverted: ${txHash}`)
// 4. Tell Auto Drive about the payment transaction (not the approval)
try {
await api.watchPaymentTransaction(intent.intentId, txHash)
} catch (error) {
// 410: the price lock has lapsed. The payment can still settle, so continue.
if (!(error instanceof PaymentApiError && error.status === 410)) throw error
}
// 5. Wait for credits. settleGraceMs keeps polling through a 410 after the lock lapses.
const status = await api.waitForPaymentCompletion(intent.intentId, {
settleGraceMs: intent.settleGraceMs,
})
return { txHash, status } // 'COMPLETED' | 'EXPIRED' | 'FAILED' | 'OVER_CAP'
}Handling Errors
When Auto Drive refuses a payment request, the SDK throws a PaymentApiError with the HTTP status and, for coded errors, a machine-readable code. Branch on code, not on message.
code | Status | What to do |
|---|---|---|
PRICE_ORACLE_UNAVAILABLE | 503 | Retry the same request later |
PRICE_UNSTABLE | 503 | Retry the same request later |
USDC_PAYMENTS_UNAVAILABLE | 503 | USDC is closed for now — pay with AI3, or retry later |
USDC_PAYMENTS_DISABLED | 403 | USDC is not available to you — pay with AI3 |
CREDIT_CAP_EXCEEDED | 403 | The purchase would exceed your credit cap — buy less |
Some failures have no code, so check status:
- 400 — the request is invalid, for example the size is larger than the whole credit cap.
- 404 on
/intents: no credentials were sent, or the account cannot buy credits. Accounts that are not Google-registered get this, notGOOGLE_ACCOUNT_REQUIRED. The body is plain textNot Found, not JSON. - 500: a server-side failure, for example the storage price could not be read. Retry later.
- 410 — the price lock has lapsed. See Polling after the price lock.
import { PaymentApiError } from '@autonomys/auto-drive'
try {
const intent = await api.createUsdcPaymentIntent(sizeBytes)
// ...pay as above
} catch (error) {
if (!(error instanceof PaymentApiError)) throw error
switch (error.code) {
case 'PRICE_ORACLE_UNAVAILABLE':
case 'PRICE_UNSTABLE':
// retry later
break
case 'USDC_PAYMENTS_DISABLED':
case 'USDC_PAYMENTS_UNAVAILABLE':
// fall back to api.createPaymentIntent (AI3)
break
default:
throw error
}
}Polling after the Price Lock
GET /intents/:id answers 410 once the price lock has lapsed on an intent that has no recorded transaction hash — for example when watchPaymentTransaction itself got a 410. With a recorded hash, the 410 starts only when Auto Drive stops accepting payments for the intent, currently 20 minutes after expiresAt. A payment sent near the end of the lock can still be credited after the first 410.
With settleGraceMs set, waitForPaymentCompletion keeps polling through 410 for that long and only then returns 'EXPIRED'. A successful read in between resets the clock. Without it, a 410 throws a PaymentApiError, as in earlier SDK versions. This option works for AI3 intents too.
'EXPIRED'from this path means the SDK stopped waiting. It does not prove the payment is lost — check the account’s credits before telling a user the payment failed.- The grace is measured from the first
410the SDK sees, so wait for the payment receipt before callingwaitForPaymentCompletion. - Keep
timeoutMs(default 5 minutes) larger than the time left on the lock plussettleGraceMs, or the call can throw a timeout error before it returns'EXPIRED'.
Things to Know
- Always pay
usdcAmount(quotedTokenAmount) exactly. Paying a different amount is accepted, but credits are granted in proportion to what was received. - Pay before the intent expires. Auto Drive still credits a payment for a short while after the 10-minute lock (currently up to 20 minutes after
expiresAt), but do not rely on it. A payment that arrives later is not credited automatically; it is recorded and recoverable through support. - Do not send AI3 to a USDC intent (or USDC to an AI3 intent). Payments in the wrong asset are not credited automatically.
- USDC can be temporarily closed. New USDC intents may be refused (
USDC_PAYMENTS_UNAVAILABLE,PRICE_ORACLE_UNAVAILABLE,PRICE_UNSTABLE) for short periods. An intent that was already quoted stays payable until it expires. Fall back to AI3 if needed.
Using Credits After Purchase
Once purchased, credits are consumed automatically when uploading via the @autonomys/auto-drive SDK. No additional configuration is needed.
import { createAutoDriveApi } from '@autonomys/auto-drive'
import { NetworkId } from '@autonomys/auto-utils'
const api = createAutoDriveApi({ apiKey: 'your-api-key', network: NetworkId.MAINNET })
// Credits are deducted automatically on upload
const cid = await api.uploadFileFromInput(file, {
password: 'optional-encryption-password', // enable AES-256-GCM encryption
})
console.log('Uploaded CID:', cid)Credits are consumed in FIFO expiry order — the soonest-to-expire credits are spent first.
Limits and Expiry
| Parameter | Value |
|---|---|
| Maximum purchased credits | 100 GB per account |
| Credit expiry | 90 days from grant date |
| Intent timeout | 10 minutes |
| Confirmation blocks | 6 (Auto-EVM for AI3, Ethereum for USDC) |
The 100 GB cap applies to AI3 and USDC purchases combined.