Sellers
Price an HTTP route in GNK or USDC. You return 402, the client pays, you settle through this facilitator, then you serve the work. You do not run a Gonka node.
Server loop
- If
PAYMENT-SIGNATUREis missing or not valid base64 JSON, respond 402 withPAYMENT-REQUIRED(header and body). POST/settlewithpaymentPayload(what the client sent) andpaymentRequirements(what you advertised).- If
successis false, respond 402 again and put the reason inerror. - If
successis true, do the work, then return 200 withPAYMENT-RESPONSEset to the base64 settle result.
Gonka uses the upfront payment flow. Do not serve the resource after a verify-only check. /verify is optional and read-only. /settle is what moves funds.
Advertise a price
Your 402 body is an x402 v2 PaymentRequired object. Minimum useful accepts entry:
{
"scheme": "exact",
"network": "cosmos:gonka-mainnet",
"amount": "1000000",
"asset": "ngonka",
"payTo": "gonka1yourmerchantaddress…",
"maxTimeoutSeconds": 60,
"extra": {
"name": "GNK",
"decimals": 9,
"assetTransferMethod": "signed-tx",
"paymentFlow": "upfront"
}
}Add a second object for USDC: set asset to the CW-20 address, decimals to 6, name to USDC. Encode the whole PaymentRequired object as standard base64 for the header. Field list is on Protocol.
Settle before serving
curl -sS -X POST {{BASE}}/settle \
-H 'Content-Type: application/json' \
-d '{
"x402Version": 2,
"paymentPayload": { "...from PAYMENT-SIGNATURE..." },
"paymentRequirements": { "...your accepts entry..." }
}'On success you get transaction (hex hash), payer, network, and amount. Credit your own ledger if you need one; the chain transfer is already to payTo.
The facilitator rejects a reused TxRaw (replayed_payment). Still enforce that in your app if you run more than one replica and the client retries.
Middleware sketch
async function requirePayment(req, res, next) {
const header = req.get("PAYMENT-SIGNATURE");
const required = paymentRequiredFor(req);
if (!header) return send402(res, required);
const paymentPayload = JSON.parse(Buffer.from(header, "base64").toString());
const settled = await fetch(FACILITATOR + "/settle", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
x402Version: 2,
paymentPayload,
paymentRequirements: paymentPayload.accepted,
}),
}).then((r) => r.json());
res.set("PAYMENT-RESPONSE", Buffer.from(JSON.stringify(settled)).toString("base64"));
if (!settled.success) return send402(res, { ...required, error: settled.errorReason });
next();
}Pricing
| GNK | 1 GNK = 1000000000 ngonka. Example: 0.001 GNK → amount: "1000000". |
|---|---|
| USDC | 1 USDC = 1000000. Example: $0.01 → amount: "10000". |
| Who receives | Your payTo address. The facilitator never sweeps or holds the payment. |
The demo route on this host uses tiny amounts so you can test. Your production amounts are your own.
Discovery
Optional: publish paid URLs so agents can find them. This facilitator exposes GET /discovery/resources for its own /demo. The live catalog is below and on Resource listing. You can run a similar list on your API, or register in an x402 Bazaar later. Shape is in HTTP API.