Documentation Index
Fetch the complete documentation index at: https://docs.peaq.xyz/llms.txt
Use this file to discover all available pages before exploring further.
Gas Station is a 2FA-gated faucet that funds fresh machine wallets on peaq chain so they can bond and register.
Why Gas Station exists
A newly generated machine keypair has zero balance. Before it can register an identity (which requires bonding 1 PEAQ), it needs native tokens for gas. Gas Station solves this bootstrap problem: the owner enrolls in 2FA once, then funds each machine wallet with a single SDK call.
2FA setup flow
Initiate 2FA enrollment
Call setupFaucet2FA with the owner’s address. The faucet returns an otpauthUri for manual entry and a qrImageUrl for scanning.const setup = await client.setupFaucet2FA(
ownerAddress,
"https://depinstation.peaq.network"
);
console.log(setup);
// setup.otpauthUri : paste into authenticator app
// setup.qrImageUrl : render immediately, expires in ~2 minutes
Scan QR code with authenticator app
Open any TOTP-compatible authenticator (Google Authenticator, Authy, 1Password). Scan the QR code or manually enter the otpauthUri. The QR image expires after approximately 2 minutes.
Confirm 2FA activation
Submit the current TOTP code from the authenticator app to activate 2FA for this owner address.await client.confirmFaucet2FA(
ownerAddress,
"https://depinstation.peaq.network",
"123456" // TOTP code from authenticator
);
Funding a machine wallet
After 2FA is active, fund any machine wallet with fundFromGasStation. The response is a discriminated union: either success (transfer landed) or skipped (wallet already funded).
const result = await client.fundFromGasStation(
{
ownerAddress: "0xOwner...",
targetWalletAddress: machineAddress,
chainId: "peaq",
twoFactorCode: "654321",
},
"https://depinstation.peaq.network"
);
if (result.status === "success") {
console.log("Funded:", result.txHash, result.fundedAmount);
} else {
// status === "skipped"
console.log("Already funded:", result.currentBalance);
}
Success response
JS (camelCase). The SDK retains the idempotency key on the response so callers can persist it for retry recovery:
| Field | Type | Description |
|---|
status | "success" | Transfer completed |
requestId | string | Idempotency key (echoed from request, or SDK-generated UUID) |
txHash | 0x-prefixed hex | Transaction hash of the funding transfer |
fundedAmount | string (decimal wei) | Amount transferred |
Python (snake_case). The SDK does not echo request_id on the response. If you need it for retry recovery, pass it in explicitly and hold the value yourself:
| Field | Type | Description |
|---|
status | "success" | Transfer completed |
tx_hash | 0x-prefixed hex | Transaction hash of the funding transfer |
funded_amount | string (decimal wei) | Amount transferred |
Skipped response
JS (camelCase):
| Field | Type | Description |
|---|
status | "skipped" | Wallet already has sufficient balance |
requestId | string | Idempotency key |
currentBalance | string (decimal wei) | Target wallet’s current balance |
minGasBalance | string (decimal wei) | Faucet-configured minimum threshold |
Python (snake_case):
| Field | Type | Description |
|---|
status | "skipped" | Wallet already has sufficient balance |
current_balance | string (decimal wei) | Target wallet’s current balance |
min_gas_balance | string (decimal wei) | Faucet-configured minimum threshold |
Rate limits and caps
Gas Station enforces three independent throttles to prevent abuse, plus a per-chain minimum balance threshold that decides whether a funding request transfers anything at all:
| Limit | Scope | Surfaces as | Description |
|---|
| Rate limit | Per owner | RATE_LIMITED | Too many funding requests in too short a window. Back off and retry. |
| Daily funding cap | Per owner | CAP_EXCEEDED_OWNER | Total funded amount per owner per day. |
| Daily funding cap | Per wallet | CAP_EXCEEDED_WALLET | Total funded amount per target wallet per day. |
| Minimum gas balance | Per chain | skipped response | When the target wallet already holds at least this much, the faucet returns skipped with currentBalance/current_balance and minGasBalance/min_gas_balance instead of transferring. |
Exact cap values, rate-limit windows, and the minimum gas balance are configured server-side and are subject to change. Branch on the error codes (or the skipped status) rather than hard-coding numbers.
Error codes
Gas Station defines 20 error codes. Not every endpoint can raise every code; the subset depends on what the endpoint actually does.
POST /2fa/setup: setupFaucet2FA / setup_faucet_2fa
| Code | Meaning |
|---|
INVALID_OWNER_ADDRESS | Owner address failed server-side format validation (setup-only). |
INVALID_PAYLOAD | Request body did not match the spec (e.g. unknown format). |
QR_GENERATION_FAILED | The faucet failed to render the QR image (setup-only). |
INTERNAL_ERROR | Unhandled server-side failure. |
POST /2fa/confirm: confirmFaucet2FA / confirm_faucet_2fa
| Code | Meaning |
|---|
INVALID_2FA | TOTP code did not match the secret. |
2FA_NOT_CONFIGURED | Owner never completed setup. Call setupFaucet2FA first. |
2FA_LOCKED | Owner locked after too many invalid attempts. |
INTERNAL_ERROR | Unhandled server-side failure. |
POST /faucet/fund: fundFromGasStation / fund_from_gas_station
| Code | Meaning |
|---|
INVALID_2FA | TOTP code did not match. |
2FA_NOT_CONFIGURED | Owner never completed setup. |
2FA_NOT_ACTIVE | Setup done but never confirmed. Call confirmFaucet2FA first. |
2FA_LOCKED | Owner locked after too many invalid attempts. |
DUPLICATE_REQUEST | A request with this requestId is still in flight. |
REQUEST_ALREADY_PROCESSED | This requestId has already completed. |
RATE_LIMITED | Faucet rate limit exceeded. |
CAP_EXCEEDED_OWNER | Owner daily funding cap exceeded. |
CAP_EXCEEDED_WALLET | Wallet daily funding cap exceeded. |
INVALID_PAYLOAD | Request body validation failed server-side. |
INVALID_OWNER_ADDRESS | Malformed ownerAddress. |
INVALID_TARGET_ADDRESS | Malformed targetWalletAddress. |
INVALID_CHAIN_ID | Unsupported chainId. |
INVALID_REQUEST_ID | The supplied requestId was not a valid UUID. |
TRANSFER_FAILED | On-chain transfer failed. |
CHAIN_RPC_ERROR | Faucet’s upstream RPC provider failed. |
QR_NOT_FOUND | QR token does not exist (rare; surfaces when a stale QR is referenced). |
QR_EXPIRED | QR token has expired. |
INTERNAL_ERROR | Unhandled server-side failure. The SDK also raises this code locally for non-JSON bodies and unexpected envelope shapes. |
For SDK-owned message strings and HTTP status codes per code, see errors.
Cross-links