Skip to main content
Defined in the Base Account SDK
Most developers should use charge() instead, which handles execution automatically using CDP wallets. This function is for advanced use cases requiring custom transaction handling.
The prepareCharge function prepares the necessary transaction calls to charge a subscription. It returns the array of call data objects to execute the charge through wallet_sendCalls or eth_sendTransaction. This gives you programmatic control over when and how to execute subscription charges.

When to Use This

Use prepareCharge only if you need:
  • Custom wallet infrastructure (not using CDP)
  • Manual transaction control
  • Integration with existing wallet systems
  • Client-side charging (though this is uncommon)
For standard backend subscription management, use charge() instead.

Parameters

id
string
required
The subscription ID (permission hash) returned from subscribe().Pattern: ^0x[0-9a-fA-F]{64}$
amount
string | 'max-remaining-charge'
required
Amount to charge (e.g., “10.50”) or ‘max-remaining-charge’ for the full remaining amount in the current period.
testnet
boolean
Must match the testnet setting used in the original subscribe call. Default: false

Returns

result
PrepareChargeResult
Array of transaction calls to execute the charge.
The returned array contains:
  • An approval call (if the permission is not yet active)
  • A spend call to charge the subscription
import { base } from '@base-org/account';
import { createWalletClient, http } from 'viem';
import { privateKeyToAccount } from 'viem/accounts';
import { base as baseChain } from 'viem/chains';

// Initialize wallet client with your subscription owner account
const account = privateKeyToAccount('0x...'); // Your app's private key
const walletClient = createWalletClient({
  account,
  chain: baseChain,
  transport: http()
});

// Prepare to charge a specific amount
const chargeCalls = await base.subscription.prepareCharge({
  id: '0x71319cd488f8e4f24687711ec5c95d9e0c1bacbf5c1064942937eba4c7cf2984',
  amount: '9.99',
  testnet: false
});

// Execute each charge call
const transactionHashes = [];

for (const call of chargeCalls) {
  const hash = await walletClient.sendTransaction({
    to: call.to,
    data: call.data,
    value: call.value || 0n
  });
  
  transactionHashes.push(hash);
  
  // Wait for transaction confirmation before next call
  await walletClient.waitForTransactionReceipt({ hash });
}

console.log(`Charge transactions: ${transactionHashes.join(', ')}`);
[
  {
    to: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
    data: "0x095ea7b3...",
    value: "0x0"
  },
  {
    to: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
    data: "0xa9059cbb...",
    value: "0x0"
  }
]

Error Handling

try {
  const chargeCalls = await base.subscription.prepareCharge({
    id: subscriptionId,
    amount: chargeAmount,
    testnet: false
  });
  // Execute charge
} catch (error) {
  console.error(`Failed to prepare charge: ${error.message}`);
}

Comparison with charge()

  • Using prepareCharge (Advanced)
// You manage everything manually
const chargeCalls = await base.subscription.prepareCharge({
  id: subscriptionId,
  amount: 'max-remaining-charge',
  testnet: false
});

// Initialize wallet client
const walletClient = createWalletClient({
  account: privateKeyToAccount('0x...'),
  chain: baseChain,
  transport: http()
});

// Execute each call sequentially
for (const call of chargeCalls) {
  const hash = await walletClient.sendTransaction({
    to: call.to,
    data: call.data,
    value: call.value || 0n
  });
  
  await walletClient.waitForTransactionReceipt({ hash });
}

// Handle gas estimation, nonce management, retries, etc.

Migration to charge()

If you’re currently using prepareCharge in a Node.js backend, consider migrating to charge():
Before (prepareCharge)
// Old approach - manual execution
const chargeCalls = await base.subscription.prepareCharge({
  id: subscriptionId,
  amount: '9.99',
  testnet: false
});

const walletClient = createWalletClient({
  account: privateKeyToAccount(process.env.PRIVATE_KEY),
  chain: baseChain,
  transport: http()
});

const transactionHashes = [];
for (const call of chargeCalls) {
  const hash = await walletClient.sendTransaction({
    to: call.to,
    data: call.data,
    value: call.value || 0n
  });
  
  transactionHashes.push(hash);
  await walletClient.waitForTransactionReceipt({ hash });
}
After (charge)
// New approach - automatic execution with CDP
const result = await base.subscription.charge({
  id: subscriptionId,
  amount: '9.99',
  testnet: false
});

console.log(`Charged: ${result.id}`);