Skip to main content
Every app declares itself with a JSON file served at /.well-known/bankroll.json on its own origin. Bankroll fetches it over HTTPS to learn your app’s identity, the capabilities it uses, and the wallet that receives payments. It is the root of trust for your integration: the host reads it, never your page.
/.well-known/bankroll.json
{
  "name": "Acme Games",
  "iconUrl": "https://acme.example/icon-256.png",
  "merchantWallet": "9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin",
  "capabilities": ["identity", "pay"]
}

Fields

FieldTypeDescription
namestringYour app’s display name, shown to the user in the consent prompt.
iconUrlstringHTTPS URL of your app icon (square, 256×256 recommended), shown in the consent prompt.
merchantWalletstringThe wallet address that receives every payment from pay(). Fixed here — your page can never redirect funds elsewhere. Required in every manifest, even for identity-only apps.
capabilitiesstring[]The capabilities your app uses: "identity", "pay", or both. The consent prompt asks only for what you declare.

Rules

  • Served on your origin. The manifest must live at the exact path /.well-known/bankroll.json on the same origin your app loads from. Bankroll matches by origin (scheme + host + port), so https://acme.example and https://app.acme.example are different apps with different manifests.
  • HTTPS only. The manifest, iconUrl, and your app URL must all be HTTPS.
  • Fails closed. If the manifest is missing, unreachable, or malformed, your app is granted no capability — calls to identity() and pay() reject (a missing or malformed manifest surfaces as the error code manifest_error).
  • Declares the ceiling. A capability the user can be asked for must be listed here. Calling a capability you didn’t declare rejects with capability_not_registered. See error codes.
The merchantWallet is the load-bearing security property of payments: because the recipient is pinned in a manifest the host fetches (not supplied by your page), a compromised page can at worst over-charge a consented amount to your own wallet — it can never send funds somewhere else.

Serving it

Serve the file with Content-Type: application/json at the well-known path. A couple of common setups:
// app/.well-known/bankroll.json/route.ts
export function GET() {
  return Response.json({
    name: "Acme Games",
    iconUrl: "https://acme.example/icon-256.png",
    merchantWallet: process.env.MERCHANT_WALLET,
    capabilities: ["identity", "pay"],
  });
}
app.get("/.well-known/bankroll.json", (_req, res) => {
  res.json({
    name: "Acme Games",
    iconUrl: "https://acme.example/icon-256.png",
    merchantWallet: process.env.MERCHANT_WALLET,
    capabilities: ["identity", "pay"],
  });
});
Verify it’s live before testing your app:
curl https://acme.example/.well-known/bankroll.json