Call a service
One endpoint handles free, paid, and password-protected calls.
Endpoint
POST https://device-controller.0xbs.org/quote/device/{deviceId}/service/{serviceId}
Content-Type: application/json
{ "params": { ...arguments from discovery... } }Free services
Returns the device result directly with status 201. No wallet.
curl -X POST \
https://device-controller.0xbs.org/quote/device/DEVICE_ID/service/SERVICE_ID \
-H "content-type: application/json" \
-d '{"params":{"room":"100","floor":"5"}}'Paid services (x402)
An unpaid call returns a standard x402 v1 challenge:
// HTTP 402 Payment Required
{
"x402Version": 1,
"error": "X-PAYMENT header is required",
"accepts": [
{
"scheme": "exact",
"network": "base", // base | base-sepolia | polygon | solana | solana-devnet
"maxAmountRequired": "1000000", // atomic USDC (6 decimals) → 1.0 USDC
"resource": "https://…/quote/device/…/service/…",
"payTo": "0x… / base58…",
"asset": "0x… / mint…",
"maxTimeoutSeconds": 300,
"extra": { "name": "USDC", "version": "2" }
}
]
}With x402-fetch
import { createSigner, wrapFetchWithPayment, decodeXPaymentResponse,
type MultiNetworkSigner } from "x402-fetch";
const evm = await createSigner("base", process.env.AGENT_EVM_PRIVATE_KEY!);
const svm = await createSigner("solana", process.env.AGENT_SOLANA_PRIVATE_KEY!);
const fetchWithPay = wrapFetchWithPayment(
fetch, { evm, svm } as MultiNetworkSigner, 1_000_000n);
const res = await fetchWithPay(
"https://device-controller.0xbs.org/quote/device/DEVICE_ID/service/SERVICE_ID",
{ method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ params: { room: "100", floor: "5" } }) });
console.log(await res.json());With x402-axios
import axios from "axios";
import { withPaymentInterceptor } from "x402-axios";
const client = withPaymentInterceptor(axios.create(), wallet);
const { data } = await client.post(
"https://device-controller.0xbs.org/quote/device/DEVICE_ID/service/SERVICE_ID",
{ params: { room: "100", floor: "5" } });Password-protected services
Send credentials in the body…
{
"username": "agent-alice",
"password": "s3cr3t",
"params": { "room": "100", "floor": "5" }
}…or as headers:
x-access-username: agent-alice
x-access-password: s3cr3tFor a paid and protected service, send credentials in the body and let the x402 adapter pay — the credentials are preserved across the retry.
Errors
| Status | Meaning | Action |
|---|---|---|
402 (with accepts) | payment required | let the x402 adapter pay + retry |
402 { error, detail } | verify/settle failed | read detail (funds, missing token account) |
| 401 | password protected | supply valid username + password |
| 404 | device/service not found | re-run discovery |
| 409 | paid service has no payout wallet | owner must fix it |
| 502 | pricing/processing failed | retry later |
Using an LLM assistant? See ChatGPT & Claude.