For the complete documentation index, see llms.txt. This page is also available as Markdown.

Custom Integration

POST your payment destinations to Branta from your own code — SDK or raw HTTP.

If none of the no-code gateway options fit — you run your own checkout, a custom processor, or just want full control over the request — wire Branta in directly. There are two equivalent paths: the SDK (recommended) or a raw HTTP POST.

Prerequisites

  • You've completed Platform onboarding — account, approved platform, and an API key.

  • You know which environment you're hitting (staging while testing, production for live traffic).

  • Your code can hold an API key securely — server-side only, never in a browser bundle or mobile binary.

What "integrating" means

Every time your platform issues a payment destination (on-chain address, Lightning invoice, Lightning address, etc.) to a sender, POST it to Branta. From that moment, any wallet or scanner that looks up that destination will see your name and logo. The full request/response shape is documented under Adding Payments.

Two privacy postures:

  • Plain — you send the destination as-is. Branta stores it and serves it back on lookup. Simplest, works for any destination type.

  • Zero-Knowledge — your code encrypts the destination with a per-payment secret before posting. Branta only ever sees ciphertext; only senders with the secret (delivered via the QR code) can decrypt. See Zero Knowledge for the algorithm. The SDKs handle this transparently when isZk: true is set on a destination.

The SDKs handle ZK encryption, secret generation, verify-URL building, and request shaping for you.

SDK: @branta-ops/branta (source)

import { BrantaServerBaseUrl } from "@branta-ops/branta";
import { BrantaService } from "@branta-ops/branta/v2";
import { DestinationType } from "@branta-ops/branta";
import { PrivacyMode } from "@branta-ops/branta";

const service = new BrantaService({
  baseUrl: BrantaServerBaseUrl.Production,
  defaultApiKey: process.env.BRANTA_API_KEY!,
  privacy: PrivacyMode.Loose,
});

// Called whenever your platform issues a destination to a sender.
async function publishDestination(address: string) {
  const { payment, secret, verifyUrl } = await service.addPayment({
    description: "Invoice #12345",
    destinations: [
      {
        value: address,
        type: DestinationType.BitcoinAddress,
        isPrimary: true,
        isZk: true, // set false to publish in plain
      },
    ],
    ttl: 3600, // optional — seconds until Branta forgets this destination
    metadata: "order-12345", // optional — your own correlation id
  });

  // For ZK: persist `secret` alongside your order — you need it to build
  // the `branta_secret` query param when rendering the payment QR / link.
  // `verifyUrl` is the public Branta verify page for this payment.
  return { payment, secret, verifyUrl };
}

Privacy mode interacts with isZk on addPayment: in strict mode (the wallet default) all destinations must be ZK or the call throws. Strict is also the SDK default — platforms typically set privacy explicitly to loose and choose per-destination.

ttl accepts 30 seconds minimum, 1 year maximum; the server default is 7 days (604800 s). metadata is stored verbatim as a string — Branta does not parse it. The SDKs' PaymentBuilder.addMetadata(key, value) helpers build a JSON object if you want structured fields.

Option 2: Raw HTTP

If your stack isn't covered by an SDK, POST directly. Same endpoint, same shape — you handle ZK encryption yourself if you want it (see Zero Knowledge for the JavaScript reference implementation).

Full schema (all destination types, ZK fields, response shape) is on the Adding Payments reference. Authentication header rules: Authentication.

Surfacing Branta in your UI

Once the destination is posted, link senders to the verifyUrl returned by the API. You can also use website badges to indicate Branta protection at checkout, or build a custom UI per the UI guidelines.

QR code / payment URI (ZK on-chain)

For plain destinations, the payment QR is a standard BIP-21 URI (bitcoin:<address>) — no Branta params needed.

For ZK on-chain destinations, the wallet needs two extra query parameters to look up and decrypt the record:

Param
Source
Description

branta_id

payment.destinations[n].value

URL-encoded encrypted ciphertext stored in Branta

branta_secret

secret returned by addPayment

Decryption key — delivered to the sender via the QR only

The plain address stays in the URI so the wallet knows where to send; branta_id and branta_secret are only for the Branta lookup. Wallets that don't recognise these params ignore them (standard BIP-21 unknown-param behaviour).

Example — building the URI from the SDK response:

Lightning destinations (plain or ZK) use the standard lightning:<invoice> URI — no extra params needed. The wallet SDK handles the lookup automatically.

Testing

  • Use staging for any non-live work — https://staging.guardrail.branta.pro with a staging API key from the staging dashboard.

  • Validate the round-trip with scan.branta.pro and the example QR codes — your wallet-side rendering should match.

  • The SDKs expose isApiKeyValid() / IsApiKeyValidAsync() for a cheap credential health check.

Last updated