Skip to main content
OnchainDB supports multiple payment flows for different use cases. All payments are made in TIA.

Payment Methods Overview

MethodDescriptionBest For
x402 CallbackSDK invokes callback when payment neededMost applications
Auto-PayAutomatic payments via userKey authzSeamless UX
Pre-paidPayment made before requestBatch operations
Signed TransactionPre-signed tx submitted with requestAdvanced integrations

x402 Payment Callback

The recommended approach for most applications. The SDK handles the entire flow automatically:
const result = await client.store(
  {
    collection: 'posts',
    data: [{ title: 'Hello', content: 'World' }]
  },
  // Payment callback - invoked when server returns 402
  async (quote) => {
    console.log('Payment required:', quote.totalCostTia, 'TIA');
    console.log('Pay to:', quote.brokerAddress);
    console.log('Quote expires:', new Date(quote.expiresAt * 1000));

    // Execute payment via wallet
    const txHash = await wallet.sendTokens(
      quote.brokerAddress,
      quote.totalCostTia
    );

    return {
      txHash: txHash,
      network: 'mocha-4' // or 'celestia' for mainnet
    };
  },
  true // waitForConfirmation
);

X402Quote Structure

The quote object contains all payment details:
interface X402Quote {
  quoteId: string;           // Unique quote identifier
  totalCostTia: number;      // Total cost in TIA
  amountRaw: string;         // Amount in smallest units (utia)
  brokerAddress: string;     // Address to pay
  description: string;       // Payment description
  expiresAt: number;         // Unix timestamp for expiry
  chainType: 'cosmos' | 'evm' | 'solana';
  network: string;           // Network identifier
  asset: string;             // Asset identifier (e.g., "utia")
  tokenSymbol: string;       // Token symbol
  tokenDecimals: number;     // Decimal places
  paymentMethod: 'native' | 'x402-facilitator';
  facilitator?: string;      // Facilitator URL if applicable
  allOptions: X402PaymentRequirement[];
}

Auto-Pay

When users have granted authorization (authz) to the broker, payments happen automatically:
// Client configured with userKey
const client = createClient({
  endpoint: 'https://api.onchaindb.io',
  appId: 'my_app',
  appKey: 'app_xxx...',
  userKey: 'user_yyy...' // User has granted authz
});

// No callback needed - payment is automatic
const result = await client.store({
  collection: 'data',
  data: [{ content: 'example' }]
});

Pre-paid Transaction

For scenarios where you’ve already made the payment:
// Payment was made separately
const paymentTxHash = 'ABC123...';

// Include payment proof in request
const result = await client.store({
  collection: 'data',
  data: [{ content: 'example' }],
  payment_tx_hash: paymentTxHash
});

Signed Transaction

For advanced integrations where you want to submit a pre-signed transaction:
const result = await client.store({
  collection: 'data',
  data: [{ content: 'example' }],
  signed_payment_tx: {
    signed_tx_bytes: 'base64_encoded_tx',
    user_address: 'celestia1...',
    broker_address: 'celestia1broker...',
    amount_utia: 100000,
    purpose: 'data_storage'
  }
});

Wallet Integration Examples

Keplr (Browser)

import { SigningStargateClient } from '@cosmjs/stargate';

const paymentCallback = async (quote) => {
  // Connect to Keplr
  await window.keplr.enable('mocha-4');
  const signer = await window.keplr.getOfflineSignerOnlyAmino('mocha-4');
  const accounts = await signer.getAccounts();
  const userAddress = accounts[0].address;

  // Create signing client
  const client = await SigningStargateClient.connectWithSigner(
    'https://rpc-mocha.pops.one',
    signer
  );

  // Send payment
  const result = await client.sendTokens(
    userAddress,
    quote.brokerAddress,
    [{ denom: 'utia', amount: quote.amountRaw }],
    { amount: [{ denom: 'utia', amount: '20000' }], gas: '200000' }
  );

  return {
    txHash: result.transactionHash,
    network: 'mocha-4'
  };
};

CosmJS (Server)

import { DirectSecp256k1HdWallet } from '@cosmjs/proto-signing';
import { SigningStargateClient } from '@cosmjs/stargate';

const paymentCallback = async (quote) => {
  const wallet = await DirectSecp256k1HdWallet.fromMnemonic(
    process.env.MNEMONIC,
    { prefix: 'celestia' }
  );
  const [account] = await wallet.getAccounts();

  const client = await SigningStargateClient.connectWithSigner(
    'https://rpc-mocha.pops.one',
    wallet
  );

  const result = await client.sendTokens(
    account.address,
    quote.brokerAddress,
    [{ denom: 'utia', amount: quote.amountRaw }],
    { amount: [{ denom: 'utia', amount: '20000' }], gas: '200000' }
  );

  return {
    txHash: result.transactionHash,
    network: 'mocha-4'
  };
};

Networks

NetworkChain IDUse
Testnetmocha-4Development and testing
MainnetcelestiaProduction

Next Steps