Pay with AI3 — Developer Integration
This page covers how to integrate permissionless Auto Drive credit purchasing into your own application using the AutoDriveCreditsReceiver smart contract and the credits API.
For the end-user purchase walkthrough, see the Pay with AI3 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. Each purchase follows four steps:
- Your app fetches a price quote from the backend — reflects the live protocol-level DSN storage cost via a Substrate RPC connection to the Autonomys consensus chain, plus a service fee.
- Your app asks the Auto Drive backend to create a payment intent — a server-side record that locks the price and binds a
bytes32intent ID to the authenticated account for up to 10 minutes. - Your app calls
payIntent(intentId)on theAutoDriveCreditsReceivercontract on Auto-EVM, sending the exact quoted AI3 amount asmsg.value. - Your app submits the transaction hash to the watch endpoint; the backend polls for 6 block confirmations and then grants the credits.
Credits are available immediately after confirmation and can be used via the dashboard, the Auto SDK, or the REST API.
Smart Contract
| Field | Value |
|---|---|
| Contract | AutoDriveCreditsReceiver |
| Network | Autonomys Auto-EVM |
| Chain ID | 870 |
| Address | 0xBa5bed8325183c0807EcBC80C82D40Dc7Ac5cbf7 |
View on Blockscout: AutoDriveCreditsReceiver
payIntent
function payIntent(bytes32 intentId) public payable whenNotPaused;intentId is the bytes32 value returned by POST /intents/. Send the exact quoted amount as msg.value — the transaction will fail if the value does not match.
The whenNotPaused modifier allows the protocol team to pause payments in the event of a critical issue.
Event
event IntentPaymentReceived(bytes32 indexed intentId, uint256 paymentAmount);Emitted on successful payment. Listen for this event to confirm receipt before calling the watch endpoint.
Payment Intent State Machine
PENDING ──► CONFIRMED ──► COMPLETED
│
├──► EXPIRED (no payment received within 10 minutes)
│
└──► FAILED (payment amount below the quoted price)
CONFIRMED ──► OVER_CAP (account's 100 GB purchased credit limit exceeded)Always fetch a fresh quote immediately before creating an intent. Prices reflect live protocol storage cost and can change between requests.
API Reference
Base URL: https://api.autonomys.xyz
Get a Price Quote
GET /intents/priceReturns the current AI3 cost (in Shannons) per GB. No authentication required.
Example response:
{
"pricePerGb": "1000000000000000000",
"currency": "AI3"
}Create a Payment Intent
POST /intents/Locks the current price for the authenticated account and returns an intent ID.
Authentication: Requires an Auto Drive API key (created from a Google-authenticated account).
Request body:
{
"storageGb": 10
}Response:
{
"intentId": "0xabc123...",
"amount": "10000000000000000000",
"expiresAt": "2026-05-12T12:10:00Z"
}Pass intentId as the argument to payIntent and amount as msg.value.
Confirm a Transaction
POST /intents/:id/watchSubmit the on-chain transaction hash. The backend polls for 6 confirmations before crediting the account.
Request body:
{
"txHash": "0xdef456..."
}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.
import { ethers } from 'ethers'
const CONTRACT_ADDRESS = '0xBa5bed8325183c0807EcBC80C82D40Dc7Ac5cbf7'
const ABI = [
'function payIntent(bytes32 intentId) payable',
'event IntentPaymentReceived(bytes32 indexed intentId, uint256 paymentAmount)',
]
async function purchaseCredits(signer: ethers.Signer, authToken: string, storageGb: number) {
// 1. Fetch fresh quote
const quoteRes = await fetch('https://api.autonomys.xyz/intents/price')
const { pricePerGb } = await quoteRes.json()
// 2. Create intent — price locked for 10 minutes
const intentRes = await fetch('https://api.autonomys.xyz/intents/', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${authToken}`,
},
body: JSON.stringify({ storageGb }),
})
const { intentId, amount } = await intentRes.json()
// 3. Call payIntent on Auto-EVM — send exact quoted amount
const contract = new ethers.Contract(CONTRACT_ADDRESS, ABI, signer)
const tx = await contract.payIntent(intentId, { value: amount })
await tx.wait()
// 4. Submit tx hash — backend confirms 6 blocks then grants credits
await fetch(`https://api.autonomys.xyz/intents/${intentId}/watch`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ txHash: tx.hash }),
})
return tx.hash
}Pattern 2 — User-managed credits
Direct users to the Auto Drive dashboard to purchase credits themselves using the Pay with AI3 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.
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 |