Skip to main content

Documentation Index

Fetch the complete documentation index at: https://developer.bron.org/llms.txt

Use this file to discover all available pages before exploring further.

Install

go get github.com/bronlabs/bron-sdk-go

Authenticate

Need a JWK keypair? Install the Bron CLI and run bron config init --name default --workspace <workspaceId> --key-file ~/.config/bron/keys/me.jwk --generate-key — it generates the JWK, stores it at 0600, prints the public half to paste into the Bron UI, and registers the profile. Same key file works directly with the SDK via BRON_API_KEY_FILE.
export BRON_API_KEY='{"kty":"EC","x":"VqW0Rzw4At***ADF2iFCzxc","y":"9AylQ7HHI0vRT0C***PqWuf2yT8","crv":"P-256","d":"DCQ0jrmYw8***9i64igNKuP0","kid":"cmdos3lj50000sayo6pl45zly"}'
export BRON_WORKSPACE_ID='htotobpkg7xqjfxenjid3n1o'
The SDK generates an ES256 JWT per request from your private JWK and sends it in Authorization: ApiKey <jwt>. No token caching, no revocation flow.

Quickstart

package main

import (
	"log"
	"os"

	"github.com/bronlabs/bron-sdk-go/sdk"
	"github.com/bronlabs/bron-sdk-go/sdk/types"
	"github.com/google/uuid"
	"github.com/joho/godotenv"
)

func main() {
	godotenv.Load()

	client := sdk.NewBronClient(bron.BronClientConfig{
		APIKey:      os.Getenv("BRON_API_KEY"),
		WorkspaceID: os.Getenv("BRON_WORKSPACE_ID"),
	})

	// Get workspace
	workspace, err := client.Workspaces.GetWorkspaceById()
	if err != nil {
		log.Fatal(err)
	}
	log.Printf("Workspace: %s", workspace.Name)

	// Get accounts
	accounts, err := client.Accounts.GetAccounts(nil)
	if err != nil {
		log.Fatal(err)
	}

	// Get balances for first account
	if len(accounts.Accounts) > 0 {
        account := accounts.Accounts[0]
        accountIds := []string{account.AccountId}

        balances, err := client.Balances.GetBalances(&types.BalancesQuery{
            AccountIds: &accountIds,
        })

        if err != nil {
            log.Fatal(err)
        }

        for _, balance := range balances.Balances {
            log.Printf("Balance %s (%s): %s", balance.AssetId, balance.Symbol, balance.TotalBalance)
        }

        // Create a USDC withdrawal on Ethereum to a saved address-book record.
        tx, err := client.Transactions.CreateTransaction(types.CreateTransaction{
            AccountId:       account.AccountId,
            ExternalId:      uuid.New().String(),
            TransactionType: "withdrawal",
            Params: map[string]interface{}{
                "amount":                  "100",
                "assetId":                 "5000",
                "networkId":               "ETH",
                "toAddressBookRecordId":   "<recordId>",
            },
        })

        if err != nil {
            log.Fatal(err)
        }

        log.Printf("Created transaction '%s' (%s): sent %s", tx.TransactionId, tx.Status, tx.Params["amount"])
	}
}

Subscriptions (WebSocket)

A subscription is “GET extended” — the same query you would send to the matching list endpoint, but the connection stays open. The server replays the historical match as the first frame, then keeps pushing live updates as additional frames of the same response shape (a list with one element per change in steady state).
package main

import (
	"context"
	"log"
	"os"

	"github.com/bronlabs/bron-sdk-go/sdk"
	"github.com/bronlabs/bron-sdk-go/sdk/types"
)

func main() {
	client := sdk.NewBronClient(sdk.BronClientConfig{
		APIKey:      os.Getenv("BRON_API_KEY"),
		WorkspaceID: os.Getenv("BRON_WORKSPACE_ID"),
	})

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	stream, err := client.Transactions.Subscribe(ctx, &types.TransactionsQuery{
		TransactionStatuses: &[]types.TransactionStatus{
			types.TransactionStatus_SIGNING_REQUIRED,
			types.TransactionStatus_WAITING_APPROVAL,
		},
	})
	if err != nil {
		log.Fatal(err)
	}
	defer stream.Close()

	// First batch is the historical match; subsequent batches are live updates.
	for batch := range stream.Updates() {
		for _, tx := range batch.Transactions {
			log.Printf("tx %s%s", tx.TransactionId, tx.Status)
		}
	}

	if err := stream.Err(); err != nil {
		log.Printf("stream ended: %v", err)
	}
}
  • First frame = historical match, exactly as GetTransactions(query) would return.
  • Subsequent frames = live updates, each typically a single-element list. Filters apply to both phases.
  • Skip the initial replay — pass Limit: ptr("0") (or SubscribeWithFilter(ctx, map[string]interface{}{"limit": 0, ...}) when the typed *string field doesn’t carry through; the backend wants an integer for limit).
  • Always defer stream.Close() — sends UNSUBSCRIBE and tears down the WebSocket cleanly. The channel closes when the context is cancelled, Close is called, or the connection drops; stream.Err() returns the cause.
  • Proxy is honored automatically via BronClientConfig.Proxy (or HTTP_PROXY / HTTPS_PROXY env vars).
Today only client.Transactions.Subscribe is exposed. Subscriptions for balances, approvals, and intents follow the same pattern and will land in subsequent SDK releases.

Errors

Methods return Go errors mirroring the API envelope. The error implements an interface with Code(), Trace(), Details() so callers can branch without parsing the message:
if _, err := client.Transactions.CreateTransaction(body); err != nil {
    var apiErr *sdk.APIError
    if errors.As(err, &apiErr) {
        log.Printf("api error code=%s trace=%s", apiErr.Code(), apiErr.Trace())
    }
    return err
}
Branch on Code() (stable identifier) — never on the human message. Quote Trace() in any user-facing report.

Configuration

BronClientConfig accepts:
  • APIKey — private JWK as a JSON string (required).
  • WorkspaceID — workspace ID (required).
  • BaseURL — API base URL (defaults to https://api.bron.org).
  • Proxyhttp://[user:pass@]host:port for outbound requests through a corporate proxy. Standard HTTPS_PROXY / HTTP_PROXY env vars are honored too.

Where to next

API reference

Endpoints, request/response shapes, OpenAPI spec.

CLI overview

bron binary — same auth, same data path, no client code.

Live updates (`tx subscribe`)

Same WebSocket transport, JSONL on stdout — useful for shell pipelines.

Authentication & profiles

Keypair lifecycle, env-var overrides, proxy setup, rotation.