Documentation
¶
Overview ¶
Package branta is the Go SDK for the Branta V2 API — payment destination lookup and registration with zero-knowledge encryption support.
Always use BrantaService. Never call BrantaClient directly from consumer code.
Index ¶
- Variables
- func Decrypt(encryptedValue, secret string) (string, error)
- func Encrypt(value, secret string, deterministicNonce bool) (string, error)
- func IsArk(value string) bool
- func IsBolt11(value string) bool
- func IsSilentPayment(value string) bool
- func ToNormalizedHash(value string) string
- func ToURLFragment(keys *orderedKeys) string
- type AESEncryption
- type AESEncryptionService
- type AddPaymentResult
- type BrantaClient
- func (c *BrantaClient) GetPayments(ctx context.Context, destinationValue string, options *BrantaClientOptions) ([]Payment, error)
- func (c *BrantaClient) IsAPIKeyValid(ctx context.Context, options *BrantaClientOptions) (bool, error)
- func (c *BrantaClient) PostPayment(ctx context.Context, payment Payment, options *BrantaClientOptions) (*Payment, error)
- type BrantaClientOptions
- func (o BrantaClientOptions) GetAPIKey(overrides *BrantaClientOptions) string
- func (o BrantaClientOptions) GetBaseURL(overrides *BrantaClientOptions) string
- func (o BrantaClientOptions) GetHMACSecret(overrides *BrantaClientOptions) string
- func (o BrantaClientOptions) GetPrivacy(overrides *BrantaClientOptions) PrivacyMode
- type BrantaServerBaseURL
- type BrantaService
- func (s *BrantaService) AddPayment(ctx context.Context, payment Payment, options *BrantaClientOptions) (AddPaymentResult, error)
- func (s *BrantaService) GetPayments(ctx context.Context, destinationValue, destinationEncryptionKey string, ...) (PaymentsResult, error)
- func (s *BrantaService) GetPaymentsByQRCode(ctx context.Context, qrText string, options *BrantaClientOptions) (PaymentsResult, error)
- func (s *BrantaService) IsAPIKeyValid(ctx context.Context, options *BrantaClientOptions) (bool, error)
- type Client
- type DecryptionError
- type Destination
- type DestinationType
- type EncryptionError
- type GuidSecretGenerator
- type LogoURLDomainMismatchError
- type Payment
- type PaymentBuilder
- func (b *PaymentBuilder) AddDestination(address string, destType DestinationType) *PaymentBuilder
- func (b *PaymentBuilder) AddMetadata(key, value string) *PaymentBuilder
- func (b *PaymentBuilder) Build() Payment
- func (b *PaymentBuilder) SetChildPlatform(name, logoURL, logoLightURL string) *PaymentBuilder
- func (b *PaymentBuilder) SetDescription(description string) *PaymentBuilder
- func (b *PaymentBuilder) SetPlatformLogoURL(platformLogoURL string) *PaymentBuilder
- func (b *PaymentBuilder) SetTTL(ttl int) *PaymentBuilder
- func (b *PaymentBuilder) SetZk() *PaymentBuilder
- type PaymentsResult
- type Platform
- type PrivacyMode
- type QRDestination
- type QRParser
- type RequestFailedError
- type SecretGenerator
- type UnsupportedZkDestinationTypeError
Constants ¶
This section is empty.
Variables ¶
var ( ErrPrivacyModeViolation = fmt.Errorf("PrivacyMode Strict does not permit plain-text lookups for this destination type") ErrNonZkDestinationInStrictMode = fmt.Errorf("PrivacyMode Strict requires all destinations to be ZK; one or more destinations have is_zk = false") ErrNoPaymentReturned = fmt.Errorf("No payment returned from server") ErrEncryptedDataTooShort = fmt.Errorf("invalid encrypted data: too short") ErrNoDestinations = fmt.Errorf("Payment has no destinations") ErrTampered = fmt.Errorf("The Bitcoin address in the QR code does not match the address verified by Branta. The QR code may have been tampered with.") )
Sentinel errors returned by fallible SDK operations.
Note what is deliberately absent: a QR-parse error. No sibling SDK ever raises one — QRParser degrades gracefully rather than erroring.
Decryption failures during a lookup are always swallowed internally and never surface as an error — only AddPayment's HTTP call and the logo-URL domain check are allowed to bubble an error out of BrantaService. The one decrypt-path exception is ErrTampered.
Functions ¶
func Decrypt ¶
Decrypt decrypts a value produced by Encrypt using the matching secret.
A base64 payload shorter than 28 bytes (12 iv + 16 tag minimum) is a distinct ErrEncryptedDataTooShort, checked before any crypto is attempted. Any other failure (e.g. wrong key -> GCM tag mismatch) collapses into a DecryptionError.
func Encrypt ¶
Encrypt encrypts value with a key derived from secret.
Wire format MUST match byte-for-byte across every Branta SDK:
- Key = SHA-256(UTF-8 secret bytes) — 32 bytes, used directly as the AES-256 key.
- Nonce/IV = 12 bytes. Random (CSPRNG) when deterministicNonce is false. When true: the first 12 bytes of HMAC-SHA256(key = key_data [the SHA-256'd key, NOT the raw secret], message = UTF-8 plaintext value).
- AES-256-GCM with a 16-byte tag. Wire format: base64_standard(iv || ciphertext || tag).
func IsSilentPayment ¶
IsSilentPayment reports whether value looks like a silent payment address.
func ToNormalizedHash ¶
ToNormalizedHash returns SHA-256(lowercase(value)) as 64-char uppercase hex, matching .NET's Convert.ToHexString. This value doubles as the AES secret for hash-ZK destinations, so a case mismatch here silently breaks cross-SDK payment lookups.
func ToURLFragment ¶
func ToURLFragment(keys *orderedKeys) string
ToURLFragment builds a `#k-{zk_id}={key}&k-{zk_id2}={key2}...` URL fragment from resolved decryption keys, iterating in insertion order.
Types ¶
type AESEncryption ¶
type AESEncryption interface {
Encrypt(value, secret string, deterministicNonce bool) (string, error)
Decrypt(encryptedValue, secret string) (string, error)
}
AESEncryption is the encrypt/decrypt strategy, injectable for testing.
type AESEncryptionService ¶
type AESEncryptionService struct{}
AESEncryptionService is the production AESEncryption implementation.
type AddPaymentResult ¶
AddPaymentResult is the result of AddPayment.
type BrantaClient ¶
type BrantaClient struct {
// contains filtered or unexported fields
}
BrantaClient is the production HTTP client.
func NewBrantaClient ¶
func NewBrantaClient(defaultOptions BrantaClientOptions) *BrantaClient
NewBrantaClient constructs a client with the given default options.
func (*BrantaClient) GetPayments ¶
func (c *BrantaClient) GetPayments(ctx context.Context, destinationValue string, options *BrantaClientOptions) ([]Payment, error)
GetPayments looks up payments by destination value. Lookup failures (transport, non-2xx, empty body, malformed JSON) degrade to an empty slice rather than an error. Logo-URL domain mismatches still error.
func (*BrantaClient) IsAPIKeyValid ¶
func (c *BrantaClient) IsAPIKeyValid(ctx context.Context, options *BrantaClientOptions) (bool, error)
IsAPIKeyValid hits the API-key health-check endpoint.
func (*BrantaClient) PostPayment ¶
func (c *BrantaClient) PostPayment(ctx context.Context, payment Payment, options *BrantaClientOptions) (*Payment, error)
PostPayment registers a payment. Unlike GetPayments, failures propagate.
type BrantaClientOptions ¶
type BrantaClientOptions struct {
BaseURL BrantaServerBaseURL
DefaultAPIKey string
HMACSecret string
Privacy PrivacyMode
}
BrantaClientOptions is per-service configuration, overridable per-call.
func NewBrantaClientOptions ¶
func NewBrantaClientOptions(baseURL BrantaServerBaseURL) BrantaClientOptions
NewBrantaClientOptions returns options for baseURL with PrivacyStrict and no API key or HMAC secret.
func (BrantaClientOptions) GetAPIKey ¶
func (o BrantaClientOptions) GetAPIKey(overrides *BrantaClientOptions) string
GetAPIKey resolves the effective API key, field-by-field: overrides' key wins if non-empty, else falls back to o's key. Empty string means unset.
func (BrantaClientOptions) GetBaseURL ¶
func (o BrantaClientOptions) GetBaseURL(overrides *BrantaClientOptions) string
GetBaseURL resolves the effective base URL: overrides wins if present, else o.
func (BrantaClientOptions) GetHMACSecret ¶
func (o BrantaClientOptions) GetHMACSecret(overrides *BrantaClientOptions) string
GetHMACSecret resolves the effective HMAC secret, field-by-field: overrides' secret wins if non-empty, else falls back to o's secret.
func (BrantaClientOptions) GetPrivacy ¶
func (o BrantaClientOptions) GetPrivacy(overrides *BrantaClientOptions) PrivacyMode
GetPrivacy resolves the effective privacy mode: overrides wins if present, else o.
type BrantaServerBaseURL ¶
type BrantaServerBaseURL int
BrantaServerBaseURL identifies which Branta server environment to talk to.
const ( Staging BrantaServerBaseURL = iota Production Localhost )
func (BrantaServerBaseURL) URL ¶
func (u BrantaServerBaseURL) URL() string
URL returns the base URL for this server environment (no trailing slash).
type BrantaService ¶
type BrantaService struct {
// contains filtered or unexported fields
}
BrantaService orchestrates zero-knowledge encrypt/decrypt around the raw HTTP calls in BrantaClient.
The single most important behavioral rule: decryption failures (wrong key, mismatched destination, DEK decrypt failure) are always swallowed internally — a destination that fails to decrypt is simply left encrypted (IsEncrypted = true), never surfaced as an error. The one deliberate exception: when a QR code carries both a plaintext on-chain address and branta_id/branta_secret params, a successful decrypt of the ZK Bitcoin-address destination is compared against that plaintext address, and a mismatch propagates ErrTampered.
func NewBrantaService ¶
func NewBrantaService(defaultOptions BrantaClientOptions) *BrantaService
NewBrantaService is the production constructor: real HTTP client, real AES-GCM, real UUID generator.
func NewBrantaServiceWithDeps ¶
func NewBrantaServiceWithDeps( defaultOptions BrantaClientOptions, client Client, aes AESEncryption, secretGenerator SecretGenerator, ) *BrantaService
NewBrantaServiceWithDeps is the test/advanced constructor: inject alternate implementations (e.g. mocks).
func (*BrantaService) AddPayment ¶
func (s *BrantaService) AddPayment(ctx context.Context, payment Payment, options *BrantaClientOptions) (AddPaymentResult, error)
AddPayment encrypts ZK destinations and posts the payment.
func (*BrantaService) GetPayments ¶
func (s *BrantaService) GetPayments(ctx context.Context, destinationValue, destinationEncryptionKey string, options *BrantaClientOptions) (PaymentsResult, error)
GetPayments looks up a single destination value.
func (*BrantaService) GetPaymentsByQRCode ¶
func (s *BrantaService) GetPaymentsByQRCode(ctx context.Context, qrText string, options *BrantaClientOptions) (PaymentsResult, error)
GetPaymentsByQRCode parses raw QR text and looks up matching payments.
func (*BrantaService) IsAPIKeyValid ¶
func (s *BrantaService) IsAPIKeyValid(ctx context.Context, options *BrantaClientOptions) (bool, error)
IsAPIKeyValid proxies to the HTTP client health-check.
type Client ¶
type Client interface {
GetPayments(ctx context.Context, destinationValue string, options *BrantaClientOptions) ([]Payment, error)
PostPayment(ctx context.Context, payment Payment, options *BrantaClientOptions) (*Payment, error)
IsAPIKeyValid(ctx context.Context, options *BrantaClientOptions) (bool, error)
}
Client is the raw HTTP layer. Consumers should never call this directly — go through BrantaService.
type DecryptionError ¶
type DecryptionError struct {
Err error
}
DecryptionError wraps a failed decrypt operation (wrong key, malformed ciphertext, etc). Distinct from ErrEncryptedDataTooShort.
func (*DecryptionError) Error ¶
func (e *DecryptionError) Error() string
func (*DecryptionError) Unwrap ¶
func (e *DecryptionError) Unwrap() error
type Destination ¶
type Destination struct {
Value string `json:"value"`
IsPrimary bool `json:"primary"`
IsZk bool `json:"zk"`
IsEncrypted bool `json:"-"`
Type DestinationType `json:"type,omitempty"`
ZkID string `json:"zk_id,omitempty"`
EncryptedDEK string `json:"encrypted_dek,omitempty"`
}
Destination is a payment destination exchanged with the Branta API.
Field names on the wire are snake_case (with `primary`/`zk` rather than `is_primary`/`is_zk`) and must match every other Branta SDK exactly. IsEncrypted is client-side-only derived state and is never serialized.
func NewDestination ¶
func NewDestination(value string, destType DestinationType) Destination
NewDestination constructs a destination with the given value and optional type.
type DestinationType ¶
type DestinationType string
DestinationType is the type of a payment destination.
Wire format is snake_case and MUST match every other Branta SDK exactly for cross-SDK interoperability.
const ( BitcoinAddress DestinationType = "bitcoin_address" Bolt11 DestinationType = "bolt11" Bolt12 DestinationType = "bolt12" LnUrl DestinationType = "ln_url" TetherAddress DestinationType = "tether_address" LnAddress DestinationType = "ln_address" ArkAddress DestinationType = "ark_address" SilentPayment DestinationType = "silent_payment" )
func HashZkType ¶
func HashZkType(value string) DestinationType
HashZkType returns the hash-ZK DestinationType for value, or empty if it isn't one of the three hash-ZK types (bolt11, ark, silent payment).
Intentionally returns empty for Bolt12 / LnUrl / LnAddress / TetherAddress — those are valid DestinationTypes but are NOT hash-ZK types in any sibling SDK. Do not "fix" this.
type EncryptionError ¶
type EncryptionError struct {
Err error
}
EncryptionError wraps a failed encrypt operation.
func (*EncryptionError) Error ¶
func (e *EncryptionError) Error() string
func (*EncryptionError) Unwrap ¶
func (e *EncryptionError) Unwrap() error
type GuidSecretGenerator ¶
type GuidSecretGenerator struct{}
GuidSecretGenerator is the production SecretGenerator: random UUID v4 secrets, non-deterministic nonces.
func (GuidSecretGenerator) DeterministicNonce ¶
func (GuidSecretGenerator) DeterministicNonce() bool
func (GuidSecretGenerator) Generate ¶
func (GuidSecretGenerator) Generate() string
type LogoURLDomainMismatchError ¶
type LogoURLDomainMismatchError struct {
Field string
}
LogoURLDomainMismatchError is returned when a GET response contains a logo URL whose origin does not match the configured base URL.
func (*LogoURLDomainMismatchError) Error ¶
func (e *LogoURLDomainMismatchError) Error() string
type Payment ¶
type Payment struct {
Description string `json:"description,omitempty"`
Destinations []Destination `json:"destinations"`
CreatedAt string `json:"created_at,omitempty"`
TTL int `json:"ttl"`
Metadata string `json:"metadata,omitempty"`
Platform string `json:"platform,omitempty"`
PlatformLogoURL string `json:"platform_logo_url,omitempty"`
PlatformLogoLightURL string `json:"platform_logo_light_url,omitempty"`
ParentPlatform *Platform `json:"parent_platform,omitempty"`
ChildPlatform *Platform `json:"child_platform,omitempty"`
BtcPayServerPluginVersion string `json:"btc_pay_server_plugin_version,omitempty"`
IsMetadataDecrypted bool `json:"-"`
}
Payment is the wire model for a Branta payment.
ParentPlatform is deserialize-only: set by the server, never sent on a POST. IsMetadataDecrypted is client-side-only and is never serialized.
NOTE: the majority wire name across sibling SDKs (dotnet/js/python/dart/rust) is `btc_pay_server_plugin_version`. branta-kotlin alone uses `btcpay_server_plugin_version` — a pre-existing cross-SDK inconsistency, not something to replicate here.
func (Payment) DefaultValue ¶
DefaultValue returns the value of the first destination, or ErrNoDestinations.
func (Payment) MarshalJSON ¶
MarshalJSON omits parent_platform (deserialize-only) and client-side flags.
type PaymentBuilder ¶
type PaymentBuilder struct {
// contains filtered or unexported fields
}
PaymentBuilder is a fluent builder for constructing a Payment to post.
func NewPaymentBuilder ¶
func NewPaymentBuilder() *PaymentBuilder
NewPaymentBuilder returns an empty builder.
func (*PaymentBuilder) AddDestination ¶
func (b *PaymentBuilder) AddDestination(address string, destType DestinationType) *PaymentBuilder
AddDestination adds a new destination. Call SetZk immediately after to mark it as ZK. An empty destType leaves the destination untyped.
func (*PaymentBuilder) AddMetadata ¶
func (b *PaymentBuilder) AddMetadata(key, value string) *PaymentBuilder
AddMetadata merges key/value into the payment's metadata, which is stored as a JSON-object string (i.e. double-encoded: metadata is itself the serialized form of a {key: value} map).
func (*PaymentBuilder) Build ¶
func (b *PaymentBuilder) Build() Payment
Build returns the constructed Payment.
func (*PaymentBuilder) SetChildPlatform ¶
func (b *PaymentBuilder) SetChildPlatform(name, logoURL, logoLightURL string) *PaymentBuilder
SetChildPlatform tags the payment with child-platform branding.
func (*PaymentBuilder) SetDescription ¶
func (b *PaymentBuilder) SetDescription(description string) *PaymentBuilder
SetDescription sets the payment description.
func (*PaymentBuilder) SetPlatformLogoURL ¶
func (b *PaymentBuilder) SetPlatformLogoURL(platformLogoURL string) *PaymentBuilder
SetPlatformLogoURL sets the platform logo URL.
func (*PaymentBuilder) SetTTL ¶
func (b *PaymentBuilder) SetTTL(ttl int) *PaymentBuilder
SetTTL sets the payment time-to-live in seconds.
func (*PaymentBuilder) SetZk ¶
func (b *PaymentBuilder) SetZk() *PaymentBuilder
SetZk marks the most-recently-added destination as ZK and assigns it a fresh zk_id.
type PaymentsResult ¶
PaymentsResult is the result of GetPayments / GetPaymentsByQRCode.
VerifyURL is always populated, even when Payments is empty.
type Platform ¶
type Platform struct {
Name string `json:"name,omitempty"`
LogoURL string `json:"logo_url,omitempty"`
LogoLightURL string `json:"logo_light_url,omitempty"`
}
Platform holds branding for a parent or child platform.
type PrivacyMode ¶
type PrivacyMode int
PrivacyMode controls whether plain-text (non zero-knowledge) lookups and destinations are permitted.
Strict is the default and should be used unless a QR scanner is unavailable and zero-knowledge encryption is therefore impossible.
const ( // PrivacyStrict forbids plain-text on-chain lookups and non-ZK destinations. // Never serialized over the wire. PrivacyStrict PrivacyMode = iota // PrivacyLoose removes zero-knowledge restrictions. PrivacyLoose )
type QRDestination ¶
type QRDestination struct {
Value string
Type DestinationType
}
QRDestination is a single destination parsed from QR text.
type QRParser ¶
type QRParser struct {
Destinations []QRDestination
OnChainEncryptionText string
OnChainEncryptionSecret string
}
QRParser parses raw QR text into one or more payment destinations.
Infallible by design — no sibling SDK ever raises a parse error; unrecognized input just yields a destination with an empty Type.
func (QRParser) Destination ¶
Destination returns the first destination value, if any.
func (QRParser) DestinationType ¶
func (p QRParser) DestinationType() DestinationType
DestinationType returns the first destination type, if any.
func (QRParser) IsOnChainZk ¶
IsOnChainZk is true iff both branta_id and branta_secret query params were present.
type RequestFailedError ¶
type RequestFailedError struct {
Status int
}
RequestFailedError is returned when a POST (or other mutating call) receives a non-2xx status.
func (*RequestFailedError) Error ¶
func (e *RequestFailedError) Error() string
type SecretGenerator ¶
SecretGenerator is the secret/nonce generation strategy, injectable for testing.
type UnsupportedZkDestinationTypeError ¶
type UnsupportedZkDestinationTypeError struct {
Type DestinationType
}
UnsupportedZkDestinationTypeError is returned when AddPayment is asked to encrypt a destination whose type is not a hash-ZK type and is not a Bitcoin address.
func (*UnsupportedZkDestinationTypeError) Error ¶
func (e *UnsupportedZkDestinationTypeError) Error() string
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
examples
|
|
|
branta_example
command
Command branta_example is an end-to-end usage demo.
|
Command branta_example is an end-to-end usage demo. |