Layerbeat

Agent payments

Let an AI agent add Layerbeat credit itself over HTTP 402, with x402 on Solana (pay.sh) or MPP on Tempo, from the CLI, MCP or its own code.

An agent can add personal credit to its Layerbeat account without a person paying for it: it asks for a top-up, receives 402 Payment Required, pays from its own wallet and repeats the request. Layerbeat supports two protocols:

ProtocolNetwork and tokenClientsEndpoint
x402 V2 (exact)Solana, native USDCpay (pay curl), x402 SDKsPOST /v1/billing/top-ups/x402
MPP (tempo charge)Tempo, USDC.emppx, pympp and other MPP clientsPOST /v1/billing/top-ups/mpp

Both add USD credit to the user who owns the API key. Neither buys anything by itself: the agent then orders a VPS with the API, the CLI or its MCP tools, spending that credit.

Your API key stays in Authorization

Both endpoints need a Layerbeat API key with billing:write. The payment travels in its own header (PAYMENT-SIGNATURE or Payment-Authorization), so the key and the payment never replace each other. Give agents their own key and keep keys and wallet secrets out of prompts and logs.

From start to finish

An agent with an API key (billing:read, billing:write, vm:read, vm:write) and a wallet can go from no credit to a running server:

layerbeat credit --currency USD                    # 1. what is there
layerbeat topup 10 --pay x402 --yes                # 2. add $10 from the agent's Solana wallet
layerbeat quote --region sgp --plan SG-B224 --image "Ubuntu 24.04"   # 3. price the server
layerbeat new web-1 --region sgp --plan SG-B224 --image "Ubuntu 24.04" \
  --ssh-key agent --max-price 10 --idempotency-key web-1-001 --yes --wait  # 4. buy it, never above $10

Use --pay mpp to pay with USDC.e on Tempo instead. Through MCP, the same steps are the credit, top_up (with pay), quote and create_server tools, available when the server runs with layerbeat mcp serve --allow-spend.

With the Layerbeat CLI

layerbeat topup <amount> --pay x402 runs pay and --pay mpp runs mppx to pay from this computer's wallet. See Credit.

  • The key stays in the CLI. The payer never receives your Layerbeat key: the CLI gives it a one-time address on 127.0.0.1 and forwards only this top-up.
  • The amount is capped. The CLI refuses an offer above the amount, plus the identifying suffix of under one cent.
  • It never pays twice. Retrying with the same --idempotency-key cannot pay again.

With pay.sh

pay wraps curl and pays HTTP 402 challenges from a local wallet. It sends the same request again with your headers, so the API key and idempotency key stay in place:

pay curl -X POST https://layerbeat.com/v1/billing/top-ups/x402 \
  -H "Authorization: Bearer $LAYERBEAT_API_KEY" \
  -H "Idempotency-Key: agent-topup-001" \
  -H "Content-Type: application/json" \
  --data '{"amount":"5.00"}'

The offered amount is a few micro-USDC above the round figure (for example 5.004213). That suffix identifies your payment and is kept as credit.

From code

Each example pays a $5.00 top-up and reads the API key, a top-up key and the wallet from the environment. TOPUP_KEY identifies one top-up: reuse it for every retry.

// npm install @x402/fetch @x402/svm @solana/kit @scure/base
import { x402Client, wrapFetchWithPayment } from '@x402/fetch'
import { ExactSvmScheme } from '@x402/svm/exact/client'
import { createKeyPairSignerFromBytes } from '@solana/kit'
import { base58 } from '@scure/base'

const signer = await createKeyPairSignerFromBytes(base58.decode(process.env.SVM_PRIVATE_KEY))
const client = new x402Client()
client.setSpendControls({ maxAmountPerPayment: '$5.01' }) // the amount plus the suffix
client.register('solana:*', new ExactSvmScheme(signer))
const fetchWithPayment = wrapFetchWithPayment(fetch, client)

const res = await fetchWithPayment('https://layerbeat.com/v1/billing/top-ups/x402', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    Authorization: `Bearer ${process.env.LAYERBEAT_API_KEY}`,
    'Idempotency-Key': process.env.TOPUP_KEY,
  },
  body: JSON.stringify({ amount: '5.00' }),
})
console.log(res.status, (await res.json()).status) // 201 paid

A 202 means the payment is still confirming: run the same code again with the same TOPUP_KEY.

How MPP payments are checked

The MPP challenge (WWW-Authenticate: Payment, method="tempo", intent="charge") offers two ways to pay, and both carry mppx's attribution memo for this challenge:

  • Push: your wallet broadcasts a transferWithMemo of the exact amount to the recipient, and the credential carries the transaction hash.
  • Pull: the credential carries the signed transaction and Layerbeat broadcasts it, once. Layerbeat broadcasts only a transaction that makes exactly that one call on this chain, pays its own fee and, if it expires, expires no later than the challenge.
ResponseMeaningWhat to do
402 with a challengePayment requiredPay the exact amount of currency to recipient
201 with Payment-ReceiptA final transfer credited your walletDone
202The transaction is recorded but not finalRepeat the request; do not pay again
503 payment_not_finalYour broadcast transaction is not final yetSend the same credential again in a few seconds
402 with error: payment_verification_failedThe transaction does not pay this challenge (amount, token, recipient, memo, or it failed)Check it. A transfer of the exact amount is still credited by the payment watcher

Never pay twice

  • Reuse the same Idempotency-Key for every retry of one top-up. A new key means a new payment.
  • A wallet's or facilitator's "success" is not credit. Only a finalized on-chain transfer, verified by Layerbeat, adds credit, and each transfer counts once.
  • If a request fails after you paid, replay it or check the payment. If the agent stopped right after paying, the payment watcher still credits a transfer of the exact amount.

The limits of ordinary top-ups apply: $5 minimum and $1,000 maximum per top-up, at most 5 unpaid top-ups at a time and 20 started in 24 hours, and the account must be eligible for funding. Transfers under one cent are ignored. See Credit and billing and Building with agents.