> For the complete documentation index, see [llms.txt](https://developer.branta.pro/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://developer.branta.pro/setup/wallets.md).

# Wallets

This page is for wallet developers integrating Branta into a send flow. Embedding Branta lets your users see counterparty name and logo before broadcast — turning an address or invoice into a recognizable payee.

### Why integrate Branta

* Users see *who* they are paying before broadcast (counterparty name and logo), not just an address or invoice.
* Eliminates phishing, supply-chain, address-swap, and man-in-the-middle attacks at point of transaction.
* Works across Bitcoin onchain, Lightning (bolt11, bolt12, lnurl, ln address), Ark, and Silent Payments.
* Privacy-preserving — `strict` mode never sends plain-text onchain addresses to Branta.
* No permission needed — and one network call per scan or paste.

### How Branta works for wallets

Your wallet hands raw QR text or user-pasted text to the Branta SDK. The SDK calls Branta in `strict` privacy mode: onchain destinations only resolve when the QR carries `branta_id` and `branta_secret` (ZK-encoded), while bolt11, Ark (`ark1…`), and Silent Payments (`sp1…` / `tsp1…`) resolve using hash-ZK — no secret needed. On a hit, render the returned counterparty info (name, logo, `verifyUrl`) before the user confirms send. On a miss or error, show nothing — a missing record just means the destination was never posted to Branta.

See [SDK](/tech/sdk.md), [Environments](/tech/environments.md), and [Authentication](/tech/authentication.md) for deeper reference.

### Integrate

{% tabs %}
{% tab title="JavaScript" %}
SDK: [branta-js](https://github.com/BrantaOps/branta-js)

Wallets should use `strict` privacy mode. Two flows are supported:

* **QR scan**: call `getPaymentsByQrCode` with the raw QR text. This handles both on-chain (when the QR includes `branta_id` / `branta_secret`) and lightning destinations.
* **Copy/paste**: call `getPayments` with the pasted text. Plain-text on-chain addresses will not return results in strict mode — they must be ZK-encoded. bolt11, Ark, and Silent Payments work as plain text (hash-ZK — no secret needed).

Always catch errors and show nothing on not-found — a missing record just means the address was not posted to Branta.

```ts
import { BrantaServerBaseUrl } from "@branta-ops/branta";
import { BrantaService } from "@branta-ops/branta/v2";

const service = new BrantaService({
  baseUrl: BrantaServerBaseUrl.Production,
  privacy: 'strict',
});

async function lookup(input: string, isQrCode: boolean) {
  try {
    const result = isQrCode
      ? await service.getPaymentsByQrCode(input)
      : await service.getPayments(input);

    if (result.payments.length === 0) {
      // Not found — show nothing. The address may simply not exist in Branta.
      return;
    }

    // Render result.payments and result.verifyUrl
  } catch {
    // Swallow errors — never surface a "not found" or lookup failure to the user.
  }
}
```

{% endtab %}

{% tab title=".NET" %}
SDK: [branta-dotnet](https://github.com/BrantaOps/branta-dotnet)

Wallets should use `Strict` privacy mode. Two flows are supported:

* **QR scan**: call `GetPaymentsByQrCodeAsync` with the raw QR text. This handles both on-chain (when the QR includes `branta_id` / `branta_secret`) and lightning destinations.
* **Copy/paste**: call `GetPaymentsAsync` with the pasted text. Plain-text on-chain addresses will not return results in strict mode — they must be ZK-encoded. bolt11, Ark, and Silent Payments work as plain text (hash-ZK — no secret needed).

Always catch errors and show nothing on not-found — a missing record just means the address was not posted to Branta.

```cs
using Branta.V2.Extensions;
using Branta.V2.Interfaces;

services.ConfigureBrantaServices(new BrantaClientOptions() {
    BaseUrl = BrantaServerBaseUrl.Production,
    Privacy = PrivacyMode.Strict
});
```

```cs
public class Example(IBrantaService brantaService)
{
    public async Task LookupAsync(string input, bool isQrCode)
    {
        try
        {
            var result = isQrCode
                ? await brantaService.GetPaymentsByQrCodeAsync(input)
                : await brantaService.GetPaymentsAsync(input);

            if (result.Payments.Count == 0)
            {
                // Not found — show nothing. The address may simply not exist in Branta.
                return;
            }

            // Render result.Payments and result.VerifyUrl
        }
        catch
        {
            // Swallow errors — never surface a "not found" or lookup failure to the user.
        }
    }
}
```

{% endtab %}

{% tab title="Python" %}
SDK: [branta-python](https://github.com/BrantaOps/branta-python)

Wallets should use `PrivacyMode.Strict`. Two flows are supported:

* **QR scan**: call `get_payments_by_qr_code` with the raw QR text. This handles both on-chain (when the QR includes `branta_id` / `branta_secret`) and lightning destinations.
* **Copy/paste**: call `get_payments` with the pasted text. Plain-text on-chain addresses will not return results in strict mode — they must be ZK-encoded. bolt11, Ark, and Silent Payments work as plain text (hash-ZK — no secret needed).

Always catch errors and show nothing on not-found — a missing record just means the address was not posted to Branta.

```python
from branta.enums import BrantaServerBaseUrl, PrivacyMode
from branta.options import BrantaClientOptions
from branta.v2 import BrantaService

service = BrantaService(BrantaClientOptions(
    base_url=BrantaServerBaseUrl.Production,
    privacy=PrivacyMode.Strict,
))

async def lookup(input: str, is_qr_code: bool) -> None:
    try:
        result = (
            await service.get_payments_by_qr_code(input)
            if is_qr_code
            else await service.get_payments(input)
        )

        if not result.payments:
            # Not found — show nothing. The address may simply not exist in Branta.
            return

        # Render result.payments and result.verify_url
    except Exception:
        # Swallow errors — never surface a "not found" or lookup failure to the user.
        pass
```

{% endtab %}

{% tab title="Dart" %}
SDK: [branta-dart](https://github.com/BrantaOps/branta-dart)

Wallets should use `PrivacyMode.strict`. Two flows are supported:

* **QR scan**: call `getPaymentsByQrCodeAsync` with the raw QR text. This handles both on-chain (when the QR includes `branta_id` / `branta_secret`) and lightning destinations.
* **Copy/paste**: call `getPaymentsAsync` with the pasted text. Plain-text on-chain addresses will not return results in strict mode — they must be ZK-encoded. bolt11, Ark, and Silent Payments work as plain text (hash-ZK — no secret needed).

Always catch errors and show nothing on not-found — a missing record just means the address was not posted to Branta.

```dart
import 'package:branta/branta.dart';
import 'package:http/http.dart' as http;

final options = BrantaClientOptions(
  baseUrl: BrantaServerBaseUrl.production,
  privacy: PrivacyMode.strict,
);
final brantaClient = BrantaClient(httpClient: http.Client(), defaultOptions: options);
final service = BrantaService(
  client: brantaClient,
  aesEncryption: AesEncryptionService(),
  defaultOptions: options,
);

Future<void> lookup(String input, bool isQrCode) async {
  try {
    final result = isQrCode
        ? await service.getPaymentsByQrCodeAsync(input)
        : await service.getPaymentsAsync(input);

    if (result.payments.isEmpty) {
      // Not found — show nothing. The address may simply not exist in Branta.
      return;
    }

    // Render result.payments and result.verifyUrl
  } catch (_) {
    // Swallow errors — never surface a "not found" or lookup failure to the user.
  }
}
```

{% endtab %}
{% endtabs %}

### Test your integration

Scan the [example QR codes](/setup/wallets/example-qr-codes.md) with your wallet to confirm each scenario renders the right thing before broadcast:

* **On-chain** and **Lightning** — counterparty name and logo render.
* **ZK On-chain** and **ZK Lightning** — encrypted destinations resolve via `branta_id` / `branta_secret`.
* **Not found** — your wallet shows nothing (a miss is not an error).

Each variant is published for both [Production](/setup/wallets/example-qr-codes/production.md) and [Staging](/setup/wallets/example-qr-codes/staging.md) — match the environment your SDK is pointed at.

### Wallets using Branta

See the live list at [branta.pro/network](https://branta.pro/network?tab=wallet).

To be listed, open a PR on [branta-network](https://github.com/BrantaOps/branta-network).
