dgb-x402
v0.1.0
Published
Accept DigiDollar payments from AI agents: HTTP 402 invoices, on-chain verification, deliver on confirm. The merchant half of x402 for DigiByte.
Maintainers
Readme
dgb-x402
⚠️ TESTNET ONLY — PROOF OF CONCEPT. Experimental, unaudited. It refuses to run against a non-testnet chain by default. Do not point it at real money.
Accept DigiDollar payments from AI agents. Drop-in Express middleware that
turns any route into a paid endpoint: it issues an HTTP 402 Payment Required
with a DigiDollar invoice, verifies the payment against your own node, and runs
the route once the money is actually there.
This is the merchant half of agent payments on DigiByte. The buyer half is dgb-digidollar-mcp.
import { createX402 } from "dgb-x402";
const { requirePayment } = createX402({
rpcUser: process.env.DGB_RPC_USER,
rpcPassword: process.env.DGB_RPC_PASSWORD,
wallet: "merchant",
});
app.get("/premium", requirePayment({ priceUsd: 1.00 }), (req, res) => {
res.json({ secret: "the good stuff" });
});That's it. No accounts, no API keys, no card on file — a machine pays a machine.
The flow
Agent ──GET /premium──────────────────────────▶ Store
Agent ◀──402 + { payTo: TD1..., amountUsd }──── Store ① invoice
Agent ──pays DigiDollar on-chain──────────────▶ (chain) ② payment
Agent ──GET /premium X-Payment: <invoiceId>──▶ Store ③ retry
Agent ◀──200 + the goods ────────────────────── Store ④ deliveredProven end to end on testnet26: an AI agent hit a 402, paid $1.00 in DigiDollar via MCP, retried, and got the content. An attempt to claim the goods without paying was refused.
How it can't be cheated
- A fresh DigiDollar address per invoice. Nothing else is ever paid to it, so "was this invoice paid?" collapses to "what is this address's balance?" — no guessing which payment belongs to which request.
- The client's txid is never evidence. The
X-Paymentheader carries an invoice id — a claim ticket, not proof. Payment is confirmed by asking your own node what that address holds. A lying client cannot fake a UTXO on your node. - The asset cannot be spoofed. DigiDollar has its own address type
(
DD/TD/RD) and its own UTXO set. Bare DGB sent to a DGB address does not appear inlistdigidollarutxosat all, so a merchant can't be tricked into accepting the wrong asset. - Testnet guard. Refuses to start against a non-testnet chain unless you explicitly opt out.
Honest limits — read this before pricing anything
DigiDollar has a minimum output of $1.00. Core rejects any DD output below 100 cents:
Transfer failed: Amount below minimum DigiDollar output. Minimum: 100 centsSo DigiDollar cannot do sub-dollar micropayments today. A $0.002-per-API-call model is not possible in DD. That's a real constraint on the "agents pay per call" story, and it's worth being clear about it:
- Pricing ≥ $1.00 — use DigiDollar. Stable, USD-denominated, no issuer freeze.
- Pricing < $1.00 — use raw DGB (
pay_invoice_dgbin the MCP server). No floor, but the price moves with the market.
This library enforces the floor at invoice creation with a clear error, rather than quoting a price the buyer's wallet will then refuse to pay.
Other constraints worth knowing:
- Minting DD is expensive at short lock tiers. Tier 0 (1 hour) requires ~1000% collateral — roughly 390,000 DGB per $100 of DD at current prices. Longer locks need less.
senddigidollarreads an integer as cents but a decimal as dollars (10000= $100,10000.00= $10,000). A 100x foot-gun. This library and the MCP server both normalise to integer cents.
Configuration
| Option | Default | Notes |
|--------|---------|-------|
| minConfirmations | 1 | 0 accepts on mempool — fine for cheap digital goods, risky for anything you'd miss. |
| invoiceTtlSeconds | 900 | How long an invoice stays payable. |
| persistPath | null | Persist invoices to disk so restarts don't forget who paid. |
| requireTestnet | true | Refuses to run on mainnet unless explicitly disabled. |
Run the demo
Needs a synced DigiByte testnet26 node (v9.26.4+) and a wallet.
npm install
cp .env.example .env # RPC credentials + merchant wallet
node --env-file=.env example/server.js
curl -i localhost:3402/premium # 402 + invoice
# pay it (e.g. with dgb-digidollar-mcp), then:
curl -H "X-Payment: <invoiceId>" localhost:3402/premium # the goodsNeed testnet coins? Faucet.
Independent community project. Not affiliated with the DigiByte Foundation. MIT licensed. Testnet only. Not financial software.
