# Skill: Purchase Credits on APIHub

> Pre-fund your account with USDC on Base. Each API call then debits from your balance with zero gas cost.

## Fastest: `@apihubio/cli`

```bash
npx @apihubio/cli topup 10
```

Opens the dashboard checkout in your browser. Pay with USDC on Base (any wallet), and credits appear in your balance immediately.

## Why credits?

Per-request x402 payments cost gas on every call. Credits let you pay once and make thousands of calls with no additional gas fees. Credits are checked before x402, so if you have a balance, it is used automatically.

Credits cover both APIHub-native APIs and external x402 services (when called through https://proxy.apihub.io/external or via the `apihub_call_external` MCP tool).

## Prerequisites

- An APIHub API key (see https://apihub.io/skills/register.md)
- A wallet with USDC on Base (chain ID 8453)
- Minimum purchase: $5.00 (5,000,000 microdollars)

## Step 1: Request a payment challenge

```
POST https://api.apihub.io/v1/credits/purchase
Authorization: Bearer ahk_your_key
Content-Type: application/json

{
  "amount_microdollars": 5000000
}
```

The server returns a 402 with payment requirements:
```json
{
  "x402Version": 1,
  "accepts": [{
    "scheme": "exact",
    "network": "base",
    "maxAmountRequired": "5000000",
    "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
    "payTo": "0xPlatformWallet",
    "extra": { "name": "USD Coin", "version": "2" }
  }]
}
```

## Step 2: Sign EIP-3009 TransferWithAuthorization

Construct and sign an EIP-712 typed data message authorizing the USDC transfer.

```typescript
import { createWalletClient, http } from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { base } from "viem/chains";

const account = privateKeyToAccount("0xYOUR_KEY");
const client = createWalletClient({ account, chain: base, transport: http() });

const requirements = challenge.accepts[0];
const nonce = "0x" + Array.from(crypto.getRandomValues(new Uint8Array(32)))
  .map(b => b.toString(16).padStart(2, "0")).join("");
const now = Math.floor(Date.now() / 1000);

const authorization = {
  from: account.address,
  to: requirements.payTo,
  value: requirements.maxAmountRequired,
  validAfter: String(now - 60),
  validBefore: String(now + 600),
  nonce,
};

const signature = await client.signTypedData({
  domain: {
    name: "USD Coin",
    version: "2",
    chainId: 8453n,
    verifyingContract: requirements.asset,
  },
  types: {
    TransferWithAuthorization: [
      { name: "from", type: "address" },
      { name: "to", type: "address" },
      { name: "value", type: "uint256" },
      { name: "validAfter", type: "uint256" },
      { name: "validBefore", type: "uint256" },
      { name: "nonce", type: "bytes32" },
    ],
  },
  primaryType: "TransferWithAuthorization",
  message: authorization,
});
```

## Step 3: Submit the signed payment

Encode the payment and resend the purchase request:

```typescript
const paymentPayload = {
  x402Version: 1,
  scheme: "exact",
  network: "base",
  payload: { signature, authorization },
};

const paymentSig = btoa(JSON.stringify(paymentPayload));

const res = await fetch("https://api.apihub.io/v1/credits/purchase", {
  method: "POST",
  headers: {
    "Authorization": "Bearer ahk_your_key",
    "Content-Type": "application/json",
    "PAYMENT-SIGNATURE": paymentSig,
  },
  body: JSON.stringify({ amount_microdollars: 5000000 }),
});
```

Response:
```json
{
  "ok": true,
  "data": {
    "credits_purchased": 5000000,
    "credits_display": "$5.00",
    "new_balance": 5000000,
    "new_balance_display": "$5.00",
    "transaction_hash": "0xabc..."
  }
}
```

## Step 4: Verify your balance

```
GET https://api.apihub.io/v1/credits/balance
Authorization: Bearer ahk_your_key
```

## Using @x402/fetch (simpler)

If you use the x402 client library, it handles the 402 challenge and signing automatically:

```typescript
import { wrapFetchWithPayment } from "@x402/fetch";
import { createWalletClient, http } from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { base } from "viem/chains";

const account = privateKeyToAccount("0xYOUR_KEY");
const walletClient = createWalletClient({ account, chain: base, transport: http() });
const x402Fetch = wrapFetchWithPayment(walletClient);

const res = await x402Fetch("https://api.apihub.io/v1/credits/purchase", {
  method: "POST",
  headers: {
    "Authorization": "Bearer ahk_your_key",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ amount_microdollars: 5000000 }),
});
```

## Notes

- Credits are shared across all API keys under the same profile
- Credits never expire
- Minimum purchase: $5.00
- The transaction settles on Base mainnet (USDC at 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913)
- View transactions on Basescan using the returned transaction_hash

## Related skills

- Make API calls with credits: https://apihub.io/skills/make-api-call.md
- Check your balance: https://apihub.io/skills/manage-balance.md
