buygent
v0.2.0
Published
Crypto-paid capability broker for agents.
Readme
Buygent
Crypto-paid capability broker for agents.
Buygent accepts x402 payments, provisions a resource through a provider adapter, and only settles after provisioning succeeds. The current MVP is Bun + TypeScript + Express, PostgreSQL-backed Drizzle persistence, a provider-neutral credential contract, a fake adapter for local QA, and a Twilio adapter implementation for real credential provisioning.
Implemented MVP surface
- Manual x402 flow for
verify -> provision -> settle - PostgreSQL-backed Drizzle persistence for agents, orders, payment attempts, provisions, and adapter configs
- Provider-neutral credential envelope
- Fake credential adapter for local/dev QA
- Twilio credential adapter with subaccount + API-key provisioning/revoke wiring
- CLI for config, catalog, buy, orders, credentials, and spending
Credential contract
Buygent returns credentials in a provider-neutral envelope:
{
"kind": "api-key-pair",
"fields": {
"accountSid": "...",
"apiKeySid": "...",
"apiKeySecret": "..."
}
}The public credential shape stays uniform across providers; provider-specific revoke data is stored separately and encrypted.
Environment
Copy .env.example and fill the required values:
cp .env.example .envRequired for the server:
BUYGENT_ENCRYPTION_KEY— base64 for exactly 32 bytesX402_PAY_TO— receiving address for x402 paymentsBUYGENT_PAYMENT_MODE—real(default) ormockfor provider-only integration testing
Optional adapters:
- Fake adapter: enabled by default for local testing
- RunPod adapter: set
RUNPOD_API_KEY, environment image mappings, andRUNPOD_GPU_POD_PRICE_USD_CENTS(current implementation maps buyer-facing compute intent to an internal raw pod spec) - Resend adapter: set
RESEND_API_KEY,RESEND_FROM_EMAIL, andRESEND_EMAIL_SEND_PRICE_USD_CENTS - Twilio adapter: set
TWILIO_ACCOUNT_SID,TWILIO_AUTH_TOKEN, andTWILIO_SMS_KEY_PRICE_USD_CENTS - OmOCon demo register.prepare: set
CODEF_CLIENT_ID_DEMO,CODEF_CLIENT_SECRET_DEMO,CODEF_PUBLIC_KEY, and optionallyREGISTER_PREPARE_DRY_RUN=true
OmOCon demo: kor.biz.register.prepare
kor.biz.register.prepare replaces the old Playwright-based Hometax open/submit flow.
- CODEF resident register lookup supplies the owner identity/address
- optional CODEF building-ledger lookup fills rental/area hints
- a bundled KSIC mini-catalog classifies the 업종코드
- a small rule engine recommends
general | simplified | tax_exempt pdf-librenders a 1-2 page Korean A4 guide PDF plus a Markdown checklist- the response now also includes a short bookmarklet URL plus a 10-minute single-use autofill token backed by
/actions/kor/biz/register/prepare/autofill.js
The generated guide defaults to the bundled data/fonts/NotoSansKR-Regular.otf font and writes PDFs to data/generated/register-guides/ unless REGISTER_PREPARE_BASE_URL / REGISTER_PREPARE_PDF_DIR override the output.
Hometax autofill bookmarklet
Set REGISTER_PREPARE_AUTOFILL_SECRET in production and optionally REGISTER_PREPARE_PUBLIC_BASE_URL when the public hostname differs from the PDF base URL. kor.biz.register.prepare keeps all existing output fields and adds:
autofill.bookmarkletUrl: shortjavascript:bookmarklet to save as a browser bookmarkautofill.browserScriptUrl: hosted browser-side autofill scriptautofill.valuesUrl/autofill.token: 10-minute single-use value fetch endpointautofill.instructions: Korean user guidance for the demo flow
The bookmarklet never submits the Hometax form automatically; it fills fields, shows a summary overlay, and leaves final review/submission to the user.
Local development
Install dependencies:
bun installGenerate migrations when schema changes:
bun run db:generateStart the server:
bun run dev:serverBuild and test:
bun run build
bun run testRailway deployment
Deployment scaffolding for Railway is checked in:
railway.json- start command:
bun run start - build command:
bun run build - healthcheck path:
/health
Use a Railway PostgreSQL service for persistent data. Do not mount an app volume if PostgreSQL is the target database.
Deployment notes and the full variable checklist are in docs/railway-deploy.md.
API
Public routes
GET /catalogGET /catalog?type=credentialGET /catalog/:adapterId/:listingIdGET /orders/:id/status
Agent routes
POST /agents/registerPUT /agents/limitsGET /agents/spending?walletAddress=0x...
Credential / order routes
GET /orders?walletAddress=0x...GET /credentials?walletAddress=0x...GET /credentials/:orderId
Paid route
POST /buy/:adapterId/:listingId
Content-Type: application/json
{
"walletAddress": "0x...",
"durationMin": 60
}Behavior:
- First call returns
402 Payment RequiredwithPAYMENT-REQUIRED - Client retries with
PAYMENT-SIGNATURE - Buygent verifies payment, provisions the resource, then settles
- On success, returns
200 OKwithPAYMENT-RESPONSE
Mock payment mode for provider testing
If you want to test a real provider integration without being blocked by x402 balances, set:
BUYGENT_PAYMENT_MODE=mockIn mock mode, Buygent skips x402 settlement but still performs the normal provider provisioning, order persistence, and revoke-handle storage flow. This is intended for provider integration testing only.
Intent-based paid route
Buygent also supports a common resource request contract so agents can ask for resources without knowing provider-specific IDs.
POST /buy
Content-Type: application/json
{
"walletAddress": "0x...",
"request": {
"type": "compute",
"intent": "serve a text-generation inference API",
"durationMin": 60,
"requirements": {
"gpuType": "4090",
"gpuCount": 1,
"publicEndpoint": true
}
}
}Current supported request types:
compute→ resolves to the RunPod adaptercredential→ resolves to Twilio, Resend, or explicit fake/test providers depending on requirementshuman→ resolves to the Buygent human-capacity handoff adapter
Canonical request fields:
type— current top-level resource family (compute,credential,human)- optional
resourceClass— provider-agnostic class (execution-runtime,service-access,human-capacity) intent— canonical buyer goalrequirements— class-specific required and optional inputsbilling—one_time,lease, or recognized-but-not-yet-implementedsubscription
Listings now expose a common metadata contract so a buyer-facing CLI can know what it must ask for before buying:
{
"resourceClass": "execution-runtime | service-access | human-capacity | ...",
"requiredInputs": [
{
"key": "durationMin",
"label": "Duration (minutes)",
"type": "integer"
},
{
"key": "requirements.runtime.environment",
"label": "Environment",
"type": "enum",
"options": ["pytorch", "jupyter", "vllm", "ollama"]
}
],
"optionalInputs": [
{
"key": "requirements.access.publicEndpoint",
"label": "Public endpoint",
"type": "boolean"
}
],
"billing": {
"supportedModels": ["lease"],
"defaultModel": "lease",
"defaultUnit": "minute"
},
"usableAccess": {
"modes": ["ssh", "http", "jupyter"],
"diagnosticsMode": "status-only"
}
}durationMin is a required buyer input for all current resource leases and purchases, so buyer-facing clients should always ask how long the resource is needed.
Current buyer-facing compute requirements:
- required:
task,gpuType - optional:
gpuCount,publicEndpoint
CLI
Local usage during development:
bun src/cli/index.ts config set --api-url http://127.0.0.1:3000 --wallet-address <address>
bun src/cli/index.ts catalog list --type credential
bun src/cli/index.ts buy fake/api-key --duration 60If you build first, the package also exposes a buygent bin from dist/cli/index.js.
For production-style usage, keep signing outside Buygent and configure an external signer endpoint:
buygent config set \
--api-url http://127.0.0.1:3000 \
--wallet-address <address> \
--signer-mode external \
--signer-endpoint http://127.0.0.1:4012walletKey remains supported as a dev-only local fallback.
You can also generate a local external signer endpoint automatically:
buygent signer start --wallet-key <private-key> --output urlImplemented commands:
buygent install [openclaw|hermes] [--dry-run] [--print-config] [--bundle <bundleId>] [--no-bundle]buygent config set --wallet-address ... --wallet-key ... --signer-mode local-key|external --signer-endpoint ... --api-url ... --soft-limit 50 --hard-limit 100buygent auth request-code --email <email> [--role buyer|worker] [--debug]buygent auth verify --email <email> --code <code> [--role buyer|worker]buygent auth whoamibuygent auth logoutbuygent bundle list|show|install|uninstallbuygent skill validate [skill.yaml]buygent skill bump <patch|minor|major> [skill.yaml]buygent skill publish [skill.yaml]buygent catalog list [--type credential]buygent catalog show <adapterId/listingId>buygent bounty create --market ... --specialty ... --deliverable ... --duration 60 [--intent ...] [--credential ...] [--jurisdiction ...] [--language ...] [--execution-mode ...] [--sla-min ...] [--wallet-address ...] [--output json|url]buygent buy <adapterId/listingId> --duration 60 [--output json|key]buygent orders listbuygent orders show <order-id>buygent credentials listbuygent credentials show <order-id>buygent spendingbuygent mcp --serve
v0.5 quick paths
Demand-side bootstrap:
npm install -g buygent
buygent install --dry-run
buygent installSupply-side skill workflow:
buygent skill validate skill.yaml
buygent skill bump patch skill.yaml
buygent skill publish skill.yamlMCP server mode
Buygent can run as a local stdio MCP server for agent clients. It exposes commerce tools for search, profile defaults, confirmation-gated ordering, tracking, and platform connection checks:
buygent_search— search products with{ platform, query }buygent_profile— get or set local buyer defaults with{ action: "get" | "set", profile? }; live mode stores them in~/.buygent/profile.json, while demo mode keeps them in memory. Setprofile.preferCredits: trueto default orders to the Buygent credit wallet.buygent_credits— manage the agent wallet with{ action: "balance" | "topup" | "history", amountKrw? }.balancereturns{ balanceKrw, balanceUsdCents, lastUpdated }; demotopupincrements the in-memory wallet; livetopupreturns an x402 top-up URL.buygent_order— order a product with{ productId, approve, paymentMethod?, deliveryAddress?, deliveryPhone?, paymentMethodId?, quantity?, options?, deliveryInstructions?, scheduledAt?, maxPriceUsdCents? };paymentMethodis"buygent-credits" | "card" | "x402", and product IDs returned by search are platform-prefixed (for examplefake:sku_123)buygent_confirm— approve or reject pending confirmation prompts with{ pendingOrderId, approve }buygent_track— track an order with{ orderId }buygent_connect— check platform account connection state with{ platform }
buygent_order returns { ok: false, status: "requires_confirmation", reason, prompt, pendingOrderId } before execution when a new delivery address is used, a demo-mode estimated total exceeds maxPriceUsdCents/profile budget, or scheduledAt is 30+ days in the future. Call buygent_confirm with the returned pendingOrderId to continue.
When paymentMethod: "buygent-credits" is selected (or omitted while profile.preferCredits is true), Buygent checks the local agent wallet before placing the order. If the balance is short, the tool returns { ok: false, status: "requires_topup", needKrw, prompt, topupUrl? } instead of using the user's card. When enough credit is available, the order is placed and the wallet is automatically charged after the order succeeds. Demo mode starts with ₩50,000 and prefilled sample history (one top-up and two charges); live/local credit data is stored at ~/.buygent/credits.json.
Use the normal CLI config for live API calls:
buygent config set --api-url http://127.0.0.1:3000
buygent installbuygent install currently targets the supported runtime config directly and wires Buygent MCP into that runtime. The first v0.5 live promise is capability/credits-first MCP plus curated bundle subscription; commerce session-backed flows remain out of this first install promise.
For offline demos, set BUYGENT_DEMO=1. Demo mode does not contact a Buygent API server and returns realistic sample products such as chicken and burrito orders.
Buygent credit payment flow:
- User funds the agent wallet: call
buygent_creditswithaction: "topup"andamountKrw(demo) or complete the returned x402 top-up URL (live). - Agent orders with
paymentMethod: "buygent-credits", or relies onprofile.preferCredits: true. - Buygent checks the KRW wallet balance, returns
requires_topupif short, and otherwise places the order. - After a successful order, Buygent records a
chargetransaction and the agent wallet balance decreases automatically.
Claude Code local stdio setup:
claude mcp add --transport stdio --env BUYGENT_DEMO=1 buygent -- buygent mcp --serveClaude Code tool flow example:
// 1) Save profile defaults once
{
"tool": "buygent_profile",
"arguments": {
"action": "set",
"profile": {
"defaultAddress": {
"street": "테헤란로 123",
"city": "서울특별시 강남구 역삼동",
"zipCode": "06236",
"note": "문 앞에 놓아주세요"
},
"defaultPhone": "+82-10-5555-1234",
"defaultPaymentMethodId": "pm_card_123",
"budgetPerOrderUsdCents": 5000,
"preferCredits": true
}
}
}
// 2) Check/top up the Buygent credit wallet if needed
{
"tool": "buygent_credits",
"arguments": { "action": "balance" }
}
// Demo top-up (live mode returns an x402 top-up URL instead)
{
"tool": "buygent_credits",
"arguments": { "action": "topup", "amountKrw": 30000 }
}
// 3) Place an order with delivery/payment context; preferCredits makes this use the wallet
{
"tool": "buygent_order",
"arguments": {
"productId": "fake:sku_123",
"approve": true,
"quantity": 2,
"options": { "size": "large", "spice": "medium" },
"deliveryInstructions": "경비실에 맡겨주세요"
}
}
// 4) If the response is requires_confirmation, confirm or cancel
{
"tool": "buygent_confirm",
"arguments": {
"pendingOrderId": "pending_...",
"approve": true
}
}Project .mcp.json example for Claude Code:
{
"mcpServers": {
"buygent": {
"type": "stdio",
"command": "buygent",
"args": ["mcp", "--serve"],
"env": {
"BUYGENT_DEMO": "1"
}
}
}
}Codex CLI setup:
codex mcp add buygent --env BUYGENT_DEMO=1 -- buygent mcp --serveCodex ~/.codex/config.toml example:
[mcp_servers.buygent]
command = "buygent"
args = ["mcp", "--serve"]
[mcp_servers.buygent.env]
BUYGENT_DEMO = "1"Implementation notes
- Express uses manual x402 orchestration because the stock auto-settling middleware does not preserve the required
verify -> provision -> settleorder. - Adapter configs and issued credentials are AES-256-GCM encrypted at rest.
- The fake adapter is the local QA/default test path.
- The RunPod adapter provisions one template-backed Pod and returns compute access metadata as an
opaquecredential envelope. - The Twilio adapter returns a provider-neutral
api-key-pairenvelope and stores revoke metadata for key deletion + subaccount suspension. - Buygent does not need direct access to signing secrets when the CLI is configured with an external signer endpoint.
Compute runtime MVP shape
The first compute runtime adapter is intentionally narrow:
- resource type:
compute - listing:
gpu-pod - provisioning model: one internally defined GPU pod lease
- revoke model: terminate the Pod
- returned access shape:
opaquecredential envelope with structured access fields such asaccessMode,accessReady,host,endpointUrl,sshPort,workspacePath, and provider diagnostics derived from Pod status metadata - buyer-facing required inputs:
task,environment,gpuType - buyer-facing optional inputs:
gpuCount,publicEndpoint
Required env:
RUNPOD_API_KEY=<runpod-api-key>
RUNPOD_ENV_PYTORCH_IMAGE=<image-for-pytorch-workloads>
RUNPOD_ENV_JUPYTER_IMAGE=<image-for-jupyter-workloads>
RUNPOD_ENV_VLLM_IMAGE=<image-for-vllm-workloads>
RUNPOD_ENV_OLLAMA_IMAGE=<image-for-ollama-workloads>
RUNPOD_GPU_POD_PRICE_USD_CENTS=2500
RUNPOD_MIN_DURATION_MIN=5Supported buyer-facing GPU values:
4090a100h100l40spytorchjupytervllmollama
Buygent asks the buyer for the job they want to run plus GPU intent, then maps that into an internal provider-specific pod spec. The buyer never has to provide imageName, gpuTypeIds, ports, or disk settings.
Access contract examples:
{
"kind": "opaque",
"fields": {
"podId": "...",
"status": "RUNNING",
"environment": "vllm",
"accessMode": "http",
"accessReady": true,
"host": "198.51.100.10",
"endpointUrl": "http://198.51.100.10:30000",
"authRequired": false,
"authMode": "none",
"probeMethod": "http-get",
"probeStatus": "passed",
"probeHttpStatus": 200,
"usableReady": true,
"provider": "runpod",
"diagnosticsMode": "status-only",
"providerStatus": "RUNNING"
}
}{
"kind": "opaque",
"fields": {
"podId": "...",
"status": "RUNNING",
"environment": "pytorch",
"accessMode": "ssh",
"accessReady": true,
"host": "198.51.100.20",
"sshPort": 30222,
"workspacePath": "/workspace",
"authRequired": true,
"authMode": "ssh-public-key",
"authConfigured": true,
"probeMethod": "auth-configured",
"probeStatus": "pending_buyer_verification",
"usableReady": false,
"provider": "runpod",
"diagnosticsMode": "status-only",
"providerStatus": "RUNNING"
}
}Current diagnostics source:
- Programmatic Pod status/metadata: supported via RunPod Pod API /
runpodctl get pod --allfields - Raw system/container log bodies: currently documented in RunPod UI, not surfaced by Buygent's access contract yet
- Authenticated usable probes currently supported: public HTTP endpoints only
- SSH/Jupyter access return explicit auth requirements and configuration state. For SSH, buyers can provide
requirements.auth.sshPublicKey, which Buygent injects asSSH_PUBLIC_KEYinto the pod.
Example request body:
{
"walletAddress": "0x...",
"request": {
"type": "compute",
"intent": "serve a text-generation inference API",
"durationMin": 60,
"billing": {
"model": "lease",
"unit": "minute",
"autoRenew": false
},
"requirements": {
"runtime": {
"environment": "vllm"
},
"accelerator": {
"gpuType": "4090",
"count": 1
},
"access": {
"publicEndpoint": true
},
"auth": {
"sshPublicKey": "ssh-ed25519 AAAA... buyer@example"
}
}
}
}Canonical compute contract uses nested runtime, accelerator, and access fields. The older flat aliases (environment, gpuType, gpuCount, publicEndpoint) are still accepted for backward compatibility.
CLI example:
buygent buy runpod/gpu-pod --duration 60 \
--task "serve a text-generation inference API" \
--environment vllm \
--gpu-type 4090 \
--public-endpointCommon CLI example:
buygent buy --type compute \
--intent "serve a text-generation inference API" \
--duration 60 \
--task "serve a text-generation inference API" \
--environment vllm \
--gpu-type 4090 \
--public-endpointCredential CLI example:
buygent buy --type credential \
--intent "send SMS via API" \
--duration 60 \
--channel sms \
--provider twilioResend capability example:
{
"walletAddress": "0x...",
"request": {
"type": "credential",
"resourceClass": "service-access",
"intent": "send transactional email",
"durationMin": 60,
"billing": {
"model": "one_time",
"unit": "minute",
"autoRenew": false
},
"requirements": {
"provider": "resend",
"channel": "email"
}
}
}Successful mediated capabilities may also include a short-lived Buygent access token in the buy response:
{
"access": {
"authMode": "buygent-token",
"token": "<short-lived-token>",
"expiresAt": "2026-04-04T12:15:00.000Z",
"capabilities": ["send-email"]
}
}For SSH-mode compute resources, Buygent can also issue a short-lived compute-exec token that lets the buyer execute a one-shot command through Buygent without receiving provider SSH credentials directly.
{
"access": {
"authMode": "buygent-token",
"capabilities": ["compute-exec"]
}
}Resend CLI example:
buygent buy --type credential \
--intent "send transactional email" \
--billing one_time \
--duration 60 \
--channel email \
--provider resend
buygent email send \
--order-id <order-id> \
--to [email protected] \
--subject "Hello" \
--text "It works"buygent email send now obtains a short-lived Buygent capability token for the purchased order before invoking the email action.
Compute-exec CLI example:
buygent compute exec \
--order-id <order-id> \
--command "nvidia-smi && python -c 'import torch; print(torch.cuda.is_available())'"This uses a short-lived Buygent token and a Buygent-managed SSH key held server-side to run a one-shot command on the purchased execution runtime.
Human-capacity API example:
{
"walletAddress": "0x...",
"request": {
"type": "human",
"resourceClass": "human-capacity",
"intent": "need a specialist to file taxes",
"market": "us",
"jurisdiction": ["us-federal", "us-ca"],
"language": "en",
"durationMin": 60,
"billing": {
"model": "one_time",
"unit": "minute",
"autoRenew": false
},
"requirements": {
"specialty": "tax-preparer",
"credential": ["ea", "cpa"],
"executionMode": "preparation-and-filing",
"deliverable": "prepare and file 2025 tax return",
"slaMin": 120
}
}
}Returned human-capacity contracts now include sourcing guidance for the backend/operator layer, for example:
{
"credential": {
"fields": {
"taskId": "human_ord_...",
"status": "queued",
"fulfillmentMode": "async-ticket",
"specialty": "tax-preparer",
"market": "us",
"sourcingMode": "official-directory",
"candidateChannels": ["irs-directory", "naea", "state-cpa-society"],
"requiresCredentialVerification": true
}
}
}This lets Buygent route a request toward the right supplier channel by market and specialty instead of treating all human work as generic manual help.
Buyer agents can then poll the human task state:
GET /human-tasks/:orderIdwhich returns the current lifecycle state and the queued task contract.
For the planned delegated-execution marketplace model, see docs/human-execution-architecture.md.
Run your own worker
Self-hosted marketplace capabilities can be dispatched with one command once the worker account, agent profile, and capability are already registered:
buygent worker run \
--skill my-handle/my-capability \
--exec ./worker-dispatch.shThe worker CLI:
- reuses the agent key in
~/.buygent/config.json - opens the marketplace SSE stream for the selected capability
- validates each job payload against the capability
payloadJsonSchema - accepts the job, runs your handler, then completes or cancels the job automatically
- retries
/completeup to three times with exponential backoff before cancelling the job for refund safety - drains in-flight work on
SIGINT/SIGTERM
Exec contract
--exec receives the job payload as JSON on stdin and must print JSON on stdout:
#!/usr/bin/env bash
payload="$(cat)"
printf '{"received":%s}\n' "$payload"Example with explicit tuning:
buygent worker run \
--skill my-handle/my-capability \
--exec ./worker-dispatch.sh \
--concurrency 4 \
--drain-seconds 30JS module contract
Use --js ./worker.mjs to run an in-process module instead of spawning a subprocess. Export either default or run:
export default async function run(payload) {
return { ok: true, payload };
}Non-custom proof kinds
custom capabilities can rely on the generated default proof value. If a capability requires another proof kind such as callId or url, return a JSON envelope with both result and proof:
{
"result": { "ok": true },
"proof": { "kind": "callId", "value": "call_123" }
}Failure reasons
Accepted jobs are cancelled automatically when the handler fails:
- non-zero exit:
worker_failure_exit_<code> - invalid JSON stdout:
worker_failure_invalid_json - JS exception:
worker_failure_js - timeout:
worker_failure_timeout - completion persistence exhausted after retries:
worker_failure_completion
Human-capacity CLI example:
Buyer bounty create shortcut:
buygent auth request-code --email [email protected] --role buyer --debug
buygent auth verify --email [email protected] --role buyer --code 123456
buygent bounty create \
--intent "need a specialist to file taxes" \
--market us \
--specialty tax-preparer \
--credential ea \
--jurisdiction us-federal \
--language en \
--execution-mode preparation-and-filing \
--deliverable "prepare and file 2025 tax return" \
--duration 60 \
--sla-min 120This prints the created task_id plus buyer login/review URLs so the buyer can switch to the review UI.
buygent buy --type human \
--intent "need a specialist to file taxes" \
--market us \
--jurisdiction us-federal \
--language en \
--billing one_time \
--duration 60 \
--specialty tax-preparer \
--credential ea \
--execution-mode preparation-and-filing \
--deliverable "prepare and file 2025 tax return" \
--sla-min 120Verified Ethereum Sepolia PayAI flow
The currently verified end-to-end payment path uses the hosted PayAI/x402 facilitator:
- network:
eip155:11155111(Ethereum Sepolia) - asset: Sepolia USDC
0x1c7d4b196cb0c7b01d743fbc6116a902379c7238 - payment method: exact + Permit2
- facilitator: hosted PayAI/x402 facilitator (
https://x402.org/facilitator) - adapter:
fake/api-key
Required env for Buygent API
Example .env values for the verified Sepolia path:
PORT=3000
DATABASE_URL=postgresql://postgres:[email protected]:5432/buygent
BUYGENT_ENCRYPTION_KEY=<32-byte-base64-key>
X402_FACILITATOR_URL=https://x402.org/facilitator
X402_FACILITATOR_AUTH_MODE=none
X402_PAY_TO=<receiving-wallet-address>
X402_NETWORK=eip155:11155111
X402_ASSET_ADDRESS=0x1c7d4b196cb0c7b01d743fbc6116a902379c7238
X402_ASSET_NAME=USD Coin
X402_ASSET_VERSION=2
X402_ASSET_DECIMALS=6
X402_ASSET_TRANSFER_METHOD=permit2
X402_MAX_TIMEOUT_SECONDS=300
FAKE_ADAPTER_ENABLED=true
FAKE_ADAPTER_PRICE_USD_CENTS=500Verified command sequence
- Start Buygent with Sepolia config:
export X402_FACILITATOR_URL=https://x402.org/facilitator
export X402_FACILITATOR_AUTH_MODE=none
export X402_NETWORK=eip155:11155111
bun run dev:server- Start a local signer and configure the CLI:
SIGNER_URL=$(buygent signer start --wallet-key <buyer-private-key> --output url)
buygent config set \
--api-url http://127.0.0.1:3000 \
--wallet-address <buyer-address> \
--signer-mode external \
--signer-endpoint "$SIGNER_URL"- Execute the verified payment flow:
buygent buy fake/api-key --duration 60
buygent orders list
buygent spendingExpected outcome:
buyreturnssettlement.success: trueorders listshowsstatus: activespendingshowstotalSpentUsdCents: 500
Current QA baseline
bun run buildbun run test- Live HTTP QA against the fake adapter flow
- Live CLI QA against a fake x402-capable local server
- Live CLI QA against the hosted PayAI/x402 Sepolia facilitator with successful settlement
Common billing contract
The shared resource request path supports a common billing object:
{
"model": "one_time | lease | subscription",
"unit": "minute | hour | day | week | month",
"autoRenew": false,
"intervalCount": 1,
"cancelAtPeriodEnd": false
}Current behavior:
one_timeandleaseare supportedsubscriptionnow creates a durable subscription record and returnssubscriptionId/current period state, but renewal automation is still not implementeddurationMinis still required in the current MVP flow- explicit adapter routes default to
leasebilling semantics
Intent-based API example:
{
"walletAddress": "0x...",
"request": {
"type": "credential",
"intent": "send SMS via API",
"durationMin": 60,
"billing": {
"model": "one_time",
"unit": "minute",
"autoRenew": false
},
"requirements": {
"channel": "sms",
"provider": "twilio"
}
}
}Subscription example:
{
"walletAddress": "0x...",
"request": {
"type": "credential",
"resourceClass": "service-access",
"intent": "monthly messaging access",
"durationMin": 60,
"billing": {
"model": "subscription",
"unit": "month",
"intervalCount": 1,
"autoRenew": true,
"cancelAtPeriodEnd": false
},
"requirements": {
"provider": "fake"
}
}
}CLI example:
buygent buy --type credential \
--intent "send SMS via API" \
--billing one_time \
--duration 60 \
--channel sms \
--provider twilioLast tested: 2026-04-21 22:21 UTC
