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.
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.
One session, one 8-character code, three ways to learn it settled.
One truth: the settled transaction digest on Sui.
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.
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>.
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.
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.
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"
}
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.
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.
Merchants never trust a client report — every confirmation path ends at the same chain read.
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.
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.
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.
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.
Every open session is discoverable and payable by AI agents running Brisk agent wallets — no extra work on your side.
An agent calls list_payment_links with your business name (or an exact session code) and sees your open sessions: amount, description, expiry.
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.
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.
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.
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.
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.
Sui testnet, USDC (0xa1ec7fc0…7e29::usdc::USDC) during the public beta. Mainnet is the same integration; the coin type and endpoints move.
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.