Skip to main content

How Credits Work

ActumX uses a credit-based billing system:
  • Credits are stored in cents (USD)
  • Top up your balance to use paid endpoints
  • Credits are deducted when you settle x402 payments
  • View your balance and transaction history in real-time
In the demo version, the payment system is simulated. Real payment processors (Stripe, etc.) would be integrated for production.

Topping Up Credits

1

Make a Top-Up Request

Add credits to your account by making a POST request:
curl -X POST http://localhost:3001/v1/billing/top-up \
  -H "Content-Type: application/json" \
  -H "Cookie: YOUR_SESSION_COOKIE" \
  -d '{
    "amountCents": 5000
  }'
Response:
{
  "paymentIntentId": "pi_abc123def456",
  "addedCents": 5000,
  "balanceCents": 5000
}
2

Verify Your Balance

After topping up, your new balance is returned immediately. The system automatically:
  1. Creates a payment intent with status settled
  2. Adds a credit entry to your ledger
  3. Calculates your new total balance
From api/src/modules/billing/service.ts:68-86:
await db.insert(paymentIntents).values({
  id: intentId,
  userId: auth.user.id,
  amountCents: payload.amountCents,
  status: "settled",
  // ...
});

await db.insert(creditLedger).values({
  id: newId("ledger"),
  userId: auth.user.id,
  direction: "credit",
  amountCents: payload.amountCents,
  source: "top_up",
  // ...
});

Amount Limits

Top-up amounts must be between 1.00and1.00 and 1,000.00:
  • Minimum: 100 cents ($1.00)
  • Maximum: 100,000 cents ($1,000.00)
Requests outside this range will return a 400 error:
{
  "error": "amount_must_be_between_100_and_100000_cents"
}

Viewing Your Balance

Get a complete billing summary for your account:
curl http://localhost:3001/v1/billing/summary \
  -H "Cookie: YOUR_SESSION_COOKIE"
Response:
{
  "balanceCents": 4975,
  "topUpTotalCents": 5000,
  "usageTotalCents": 25,
  "activeApiKeys": 2,
  "x402Transactions": 1
}

Response Fields

balanceCents
number
Your current account balance in cents (USD)
topUpTotalCents
number
Total amount you’ve added to your account
usageTotalCents
number
Total amount spent on API requests
activeApiKeys
number
Number of non-revoked API keys
x402Transactions
number
Total count of x402 payment transactions

Payment History

View your complete payment history:
curl http://localhost:3001/v1/billing/payment-intents \
  -H "Cookie: YOUR_SESSION_COOKIE"
Response:
{
  "intents": [
    {
      "id": "pi_abc123def456",
      "userId": "user_xyz789",
      "amountCents": 5000,
      "status": "settled",
      "providerReference": "dummy_provider_ref123",
      "createdAt": "2026-03-03T22:30:00.000Z",
      "updatedAt": "2026-03-03T22:30:00.000Z"
    },
    {
      "id": "pi_def456ghi789",
      "userId": "user_xyz789",
      "amountCents": 10000,
      "status": "settled",
      "providerReference": "dummy_provider_ref456",
      "createdAt": "2026-03-01T15:00:00.000Z",
      "updatedAt": "2026-03-01T15:00:00.000Z"
    }
  ]
}
The endpoint returns the 50 most recent payment intents, ordered by creation date (newest first).

Understanding Credit Consumption

Credits are consumed when you:
  1. Make requests to x402 paid endpoints
  2. Settle payment challenges
  3. Complete transactions

Example Cost Structure

Quote Endpoint

Cost: 25 cents per requestEndpoint: GET /v1/protected/quote

Future Endpoints

More paid endpoints with varying costs will be added
From api/src/config/constants.ts:8:
export const X402_PAID_REQUEST_COST_CENTS = 25;

Credit Ledger System

ActumX maintains a double-entry ledger for all credit movements:

Credit Entries (Money In)

{
  "direction": "credit",
  "amountCents": 5000,
  "source": "top_up",
  "referenceId": "pi_abc123def456"
}

Debit Entries (Money Out)

{
  "direction": "debit",
  "amountCents": 25,
  "source": "api_request",
  "referenceId": "x402tx_xyz789"
}
Your balance is calculated by summing all credits and subtracting all debits from the ledger.

Handling Insufficient Balance

When trying to settle a payment without sufficient credits: Request:
curl -X POST http://localhost:3001/v1/x402/settle \
  -H "Authorization: Bearer xk_live_..." \
  -H "Content-Type: application/json" \
  -d '{"paymentId": "x402tx_abc123"}'
Response (402 Payment Required):
{
  "error": "insufficient_balance",
  "requiredCents": 25,
  "balanceCents": 10,
  "message": "Top up balance in dashboard before settling this x402 payment."
}
Always ensure you have sufficient balance before attempting to settle x402 payments.

Best Practices

Keep extra credits in your account to avoid failed requests:
  • Calculate your expected monthly usage
  • Top up with 20-30% extra as a buffer
  • Monitor your balance regularly
Use the billing summary to understand your usage:
const summary = await fetch('/v1/billing/summary').then(r => r.json());

const avgCostPerTransaction = summary.usageTotalCents / summary.x402Transactions;
console.log(`Average cost per transaction: $${avgCostPerTransaction / 100}`);
Monitor your balance programmatically and alert when low:
async function checkBalance() {
  const { balanceCents } = await fetch('/v1/billing/summary').then(r => r.json());
  
  if (balanceCents < 1000) {  // Less than $10
    console.warn('⚠️ Low balance alert: $' + (balanceCents / 100));
    // Send notification or auto-top-up
  }
}

Troubleshooting

If your balance doesn’t update after topping up:
  1. Check the response for a paymentIntentId
  2. Verify the balanceCents in the response
  3. Fetch the billing summary to confirm
  4. Check payment intents to see if the transaction was recorded
If your balance seems incorrect:The balance is calculated from the credit ledger:
// From api/src/services/credits.service.ts
const balance = SUM(credits) - SUM(debits)
Verify by checking your payment history and usage events.

Next Steps