Payment Flow
MachineMarket uses on-chain USDC payments on Base as both payment and authentication. There are no API keys — the transaction hash proves you paid.
Overview
1. Agent calculates cost → tier.hourly * duration_hours
2. Agent sends USDC on Base → ERC-20 transfer() to MM wallet
3. Agent waits for confirmation → >= 1 block confirmation
4. Agent calls POST /v1/spawn → includes tx_hash + wallet_address
5. API verifies on-chain → receipt, Transfer event, amounts
6. API provisions server → or returns errorCost calculation
Each tier has an hourly rate. Multiply by the number of hours in the chosen duration:
// Example: Small tier, 24h duration
const cost = 0.028 * 24; // = 0.672 USDC
// Tiers:
// Nano: $0.015/hr → $0.36/day → $10.80/mo
// Small: $0.028/hr → $0.67/day → $20.16/mo
// Medium: $0.055/hr → $1.32/day → $39.60/mo
// Large: $0.105/hr → $2.52/day → $75.60/mo
// Durations: 1h, 24h, 7d (168h), 30d (720h)Sending the payment
Transfer USDC (the ERC-20 at 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913) on Base to the MachineMarket recipient wallet. USDC has 6 decimals.
import { createWalletClient, http, parseUnits } from "viem";
import { base } from "viem/chains";
import { privateKeyToAccount } from "viem/accounts";
const USDC = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
const MM_WALLET = "0x..."; // MachineMarket recipient
const account = privateKeyToAccount(PRIVATE_KEY);
const client = createWalletClient({
account,
chain: base,
transport: http(),
});
const txHash = await client.writeContract({
address: USDC,
abi: [{
name: "transfer",
type: "function",
inputs: [
{ name: "to", type: "address" },
{ name: "amount", type: "uint256" },
],
outputs: [{ type: "bool" }],
}],
functionName: "transfer",
args: [MM_WALLET, parseUnits("0.672", 6)],
});What the API verifies
When you submit a tx_hash to POST /v1/spawn or POST /v1/instances/:id/extend, the API performs these checks:
- Receipt status — The transaction must have succeeded on-chain (
receipt.status === "success"). - Confirmations — At least 1 block confirmation.
- Transfer event — The API decodes the
Transfer(from, to, value)event from the USDC contract logs. - Recipient — The
toaddress must be the MachineMarket wallet. - Sender — The
fromaddress must match thewallet_addressyou submitted. - Amount — The transfer amount must be
>=the calculated cost.
Deduplication
Each tx_hash can only be used once. Attempting to reuse a transaction hash returns a 409 TX_DUPLICATE error. This prevents double-spending the same payment.
Wallet limits
A single wallet address can have at most 10 concurrent active instances (status provisioning or running). Exceeding this limit returns a 429 WALLET_LIMIT error.
Error codes
// 402 PAYMENT_INVALID — one of:
// "Transaction failed on-chain"
// "Transaction has insufficient confirmations"
// "Sender does not match claimed wallet_address"
// "Insufficient amount: expected X USDC, got Y USDC"
// "No USDC Transfer to MachineMarket wallet found in transaction"
// 409 TX_DUPLICATE
// "Transaction hash already used"
// 429 WALLET_LIMIT
// "Maximum concurrent instances reached for this wallet"viem, ethers, or any Web3 library to send the USDC transfer. See the Quickstart for a full example.