Skip to content

fintech-sdk/tink-go

Repository files navigation

tink-go

Go Reference Go 1.25+ License

A complete, production-grade Go client for the Tink Open Banking API, built with Domain-Driven Design and zero external dependencies (stdlib only).


Design: Domain-Driven Design (DDD)

The SDK is organised into three explicit, dependency-ordered layers:

Layer rules (enforced by import direction):

  • domain/ imports nothing from this module.
  • infrastructure/ imports only domain/.
  • application/ imports domain/ and infrastructure/.
  • tink.go imports only application/ and infrastructure/http.

Installation

go get github.com/iamkanishka/tink-go

Requires Go 1.25+. No external dependencies — stdlib only.


Quick start

import (
    tink    "github.com/iamkanishka/tink-go"
    domauth "github.com/iamkanishka/tink-go/domain/auth"
    domconn "github.com/iamkanishka/tink-go/domain/connectivity"
)

// 1. Create the client (one per application, safe for concurrent use).
client := tink.New(tink.Config{
    ClientID:      os.Getenv("TINK_CLIENT_ID"),
    ClientSecret:  os.Getenv("TINK_CLIENT_SECRET"),
    WebhookSecret: os.Getenv("TINK_WEBHOOK_SECRET"),
    CacheEnabled:  true,
    MaxRetries:    3,
})

// 2. Acquire an app-level token.
token, err := client.Auth.ClientCredentials(ctx, "accounts:read,transactions:read")

// 3. Create an authorization grant for an end user.
grant, err := client.Auth.CreateAuthorizationGrant(ctx, token.AccessToken,
    domauth.CreateAuthorizationGrantParams{
        ExternalUserID: "your-user-id",
        Scope:          "accounts:read,transactions:read",
    })

// 4. Redirect the user to Tink Link.
linkURL := client.Connectivity.BuildTransactionsLink(grant.Code,
    domconn.LinkURLOptions{
        Market:      "GB",
        Locale:      "en_US",
        RedirectURI: "https://yourapp.com/callback",
    })

// 5. After callback, exchange the code for a user token.
userToken, err := client.Auth.ExchangeCode(ctx,
    domauth.AuthorizationCodeParams{Code: callbackCode})

// 6. Fetch all accounts.
accounts, err := client.Accounts.ListAll(ctx, userToken.AccessToken)

// 7. Fetch all transactions with automatic pagination.
txns, err := client.Transactions.ListAll(ctx, userToken.AccessToken,
    domtxn.ListOptions{BookedDateGte: "2026-01-01"})

Error handling

Every service method returns error. Use errors.As to inspect the structured type:

import (
    goerrors     "errors"
    domainerrors "github.com/iamkanishka/tink-go/domain/errors"
)

_, err := client.Accounts.ListAll(ctx, token)
var te *domainerrors.TinkError
if goerrors.As(err, &te) {
    fmt.Printf("status=%d type=%s retryable=%v\n",
        te.StatusCode, te.Type, te.Retryable())
    // te.ErrorCode   — application error code (e.g. "TOKEN_INVALID")
    // te.RequestID   — Tink request ID for support escalation
    // te.ErrorDetails — raw parsed JSON error body
}

TinkError.Retryable() returns true for network errors, timeouts, and HTTP 408/429/500/502/503/504. The infrastructure layer retries these automatically (up to Config.MaxRetries attempts with exponential backoff + jitter).


Webhook verification

// Register typed handlers.
client.Webhooks.On("credentials.updated", func(e *domwebhook.Event) error {
    log.Printf("credentials updated: %v", e.Data)
    return nil
})
client.Webhooks.On("*", func(e *domwebhook.Event) error {
    // Wildcard — receives every event type.
    return nil
})

// In your HTTP handler:
func handleTinkWebhook(w http.ResponseWriter, r *http.Request) {
    body, _ := io.ReadAll(r.Body)
    sig := r.Header.Get("X-Tink-Signature")

    if err := client.Webhooks.Dispatch(body, sig); err != nil {
        http.Error(w, "webhook error", 500)
        return
    }
    w.WriteHeader(204)
}

Configuration reference

Field Type Default Description
ClientID string Tink application client_id (required)
ClientSecret string Tink application client_secret (required)
WebhookSecret string HMAC-SHA256 secret for webhook verification
BaseURL string https://api.tink.com Override for testing/staging
Timeout time.Duration 30s Per-request HTTP deadline
MaxRetries int 3 Max retry attempts on transient errors
CacheMaxSize int 512 In-memory LRU cache capacity
CacheEnabled bool false Enable GET-response caching

Running the example

export TINK_CLIENT_ID=your_client_id
export TINK_CLIENT_SECRET=your_client_secret
go run ./examples/quickstart/

License

Apache-2.0. See LICENSE.

Packages

 
 
 

Contributors

Languages