Brisk Docs

Accept USDC in your checkout
with one API call.

The Brisk Store Gateway is a headless payment gateway on Brisk's rails: create a checkout session, send the customer to a hosted pay page, and confirm settlement from the chain. No new wallet infrastructure, no crypto UX to build, no merchant fees.

Overview

How a payment flows

One session, one 8-character code, three ways to learn it settled.

⚡

Zero fees, zero gas

Stablecoin transfers at the protocol level: the customer pays no gas and you pay no processing fee. Settlement is direct into your till's on-chain balance, sub-second.

</>

One call to integrate

A session is a single POST. Everything else — zkLogin (Google sign-in, no seed phrase), the pay UI, QR fallback — is hosted for you at /pay/<code>.

🤖

Agent-payable by default

AI agents discover your open sessions by business name and pay them over MCP, within on-chain spending caps you're protected by. Same till, same webhook.

Quickstart

From zero to a paid order in three calls

1

One-time setup (in the Brisk app)

Create your merchant profile (your business name is what shoppers' agents search by) and register a till — your on-chain receiving address. Payments land in the till instantly; a daily sweep drains it to your treasury automatically.

2

Create a checkout session (your backend)

One POST when your customer reaches the payment step:

POST https://api.briskpay.app/api/checkout/sessions
Authorization: Bearer sk_live_your-key-here
Content-Type: application/json

{
  "sender":       "0x...your-owner-address...",
  "merchantId":   "0x...your-merchant-id...",
  "tillId":       "0x...your-till-id...",
  "amountMicros": 24990000,
  "description":  "Order #1042 — 2× widget",
  "metadata":     { "orderId": "1042" },
  "successUrl":   "https://yourstore.com/order/1042/complete",
  "cancelUrl":    "https://yourstore.com/checkout",
  "expiresInSec": 3600
}

Amounts are USDC micros (6 decimals): 24990000 = $24.99. Response:

{
  "code": "aB3xK9zQ",
  "url": ".../p/aB3xK9zQ",
  "hosted_checkout_url": ".../pay/aB3xK9zQ",
  "verify_url": ".../api/links/aB3xK9zQ/verify/<DIGEST>",
  "status": "pending",
  "expiresAt": "2026-09-25T14:32:00.000Z"
}
3

Send the customer to the hosted page

Redirect to hosted_checkout_url (or send url in an email / render it as a QR — the code is the invoice). The page handles Google sign-in, shows the amount, and pays USDC on Sui. On success it redirects to your successUrl with ?code=…&digest=… appended.

4

Verify before you fulfill

Call the verify endpoint with the digest from the redirect (or your webhook):

GET /api/links/aB3xK9zQ/verify/<digest>

→ { "verified": true, "status": "paid",
        "amountMicros": 24990000, "digest": "..." }

This reads the Sui chain directly and confirms the transaction credited your payee for at least the session amount. It's the authoritative check — idempotent, safe to call repeatedly.

Confirming settlement

Three transports, one truth

Merchants never trust a client report — every confirmation path ends at the same chain read.

1

Browser callback

The hosted page redirects to your success_url ~2.5 s after payment with ?code=&digest= appended. Verify immediately on page load — this is the fastest path to a confirmed order.

2

Signed webhook

Register once per session: POST /api/links/<code>/webhook with {"sender": "...", "url": "https://yourstore.com/hooks/brisk"}. You receive checkout.paid events signed in the x-brisk-signature: t=<ts>,v1=<hex> header — HMAC-SHA256 of "<t>.<rawBody>" with your secret. Reject if older than 5 minutes.

3

Polling

Prefer pull? GET /api/links/<code>/full returns the session's public status and metadata; /verify/<digest> is the authoritative chain read. No webhook infrastructure required.

Trust model. A webhook is a trigger to verify, never the verification itself: it tells you that to check, and /verify tells you whether it settled. The webhook payload is chain-verified before it fires and carries verified: true plus amount_micros, payee and merchant — but confirm via /verify before shipping goods. One settled digest satisfies at most one session; replays are rejected server-side.

Webhook signature check (Node.js)

import crypto from "node:crypto";

export function verifyBriskWebhook(rawBody, header, secret) {
  const m = /^t=(\d+),v1=([0-9a-f]{64})$/.exec(header ?? "");
  if (!m) return false;
  const [, t, v1] = m;
  if (Math.abs(Date.now() - Number(t)) > 300_000) return false; // stale
  const expected = crypto.createHmac("sha256", secret)
    .update(`${t}.${rawBody}`).digest("hex");
  return crypto.timingSafeEqual(Buffer.from(v1, "hex"), Buffer.from(expected...));
}

The webhook secret is shown exactly once at registration — store it. Re-registering rotates it atomically. Replay protection is on your side: reject any (t, v1) pair you've already accepted.

Agentic checkout

Your store, open to AI shoppers

Every open session is discoverable and payable by AI agents running Brisk agent wallets — no extra work on your side.

🔍

Discovery

An agent calls list_payment_links with your business name (or an exact session code) and sees your open sessions: amount, description, expiry.

💳

Payment

pay_invoice_link_v2 pays a session by code with a required idempotency key — a retry can never double-pay. On-chain per-transaction and 24-hour caps bound every agent.

🔒

Attribution bound

Sessions can only name a till or payee that belongs to the claimed merchant — a fake storefront cannot ride your business name into agent discovery.

Money lands in the same till as human payments, and your webhook fires the same way. You'll know an order came from an agent only if you put that in metadata — by design, it's just another customer.

Good to know

Limits & current gaps

What does it cost?

Nothing per payment. Brisk's model is a yield spread on idle balances — settlement is a direct USDC transfer into your till with no processing fee and no gas for either side.

Auth model for session creation?

Session creation accepts a merchant API key: Authorization: Bearer *** Mint keys in the Brisk app (owner-address gated); the key is bound to your merchant at creation, so the API derives merchant/till/payee from the key — the request body cannot override them. Keys are shown once, revocable instantly, and listed by last-4 hint. Unauthenticated calls still work in the platform's legacy self-declared-sender posture with strict attribution binding, so existing flows keep working; the authenticated path is the trusted one. Setting REQUIRE_MERCHANT_KEY=1 on the deployment closes the legacy path entirely — key-only.

Amounts, expiry, refunds?

One amount per session (line-item pricing and subscriptions are future work). Sessions expire — default 24h, configurable up to 30 days. Refunds are manual today: send USDC back to the customer's address from your till sweep destination.

Which network / coin?

Sui testnet, USDC (0xa1ec7fc0…7e29::usdc::USDC) during the public beta. Mainnet is the same integration; the coin type and endpoints move.

What do my customers need?

A browser. The hosted page handles everything: Google sign-in creates a self-custodial zkLogin wallet (no seed phrase, no app install), and the payment is two taps. Customers with the Brisk app can also pay by tapping their phone (NFC) or scanning your QR.