Skip to content
Indiana
Dashboard
Docs
Browse docs / Go

Go

A goroutine-safe server client for Customers, holdings, entitlement checks and usage.

API v1Updated

Install

terminalShell
go get tinker.cash/sdk/go@v0.6.0

Version v0.6.0, Go 1.23+. Installs through Go's default module proxy and checksum database.

Related: Installation details

Client

main.goGo
package main import (	"context"	"log"	"os" 	indiana "tinker.cash/sdk/go") func main() {	client, err := indiana.NewClient(indiana.Config{		APIKey:      os.Getenv("INDIANA_API_KEY"),		ProjectID:   os.Getenv("INDIANA_PROJECT_ID"),		Environment: indiana.Sandbox,		BaseURL:     os.Getenv("INDIANA_API_URL"),	})	if err != nil {		log.Fatal(err)	}	defer client.Close() 	ctx := context.Background()	customer, err := client.GetOrCreateCustomer(ctx, indiana.CreateCustomerParams{		ExternalUserID: indiana.Ptr("merchant-user-123"),	})	if err != nil {		log.Fatal(err)	} 	access, err := client.CheckEntitlement(ctx, indiana.CheckEntitlementParams{		CustomerID: customer.Customer.ID,		Requirement: indiana.CheckEntitlementParamsRequirement{			InternalFeatureID: os.Getenv("INDIANA_FEATURE_ID"),			Quantity:          "1",			Properties:        map[string]any{},		},	})	if err != nil {		log.Fatal(err)	}	if !access.Check.Allowed {		return	} 	usage, err := client.TrackUsage(ctx, indiana.TrackUsageParams{		CustomerID: customer.Customer.ID,		Command: indiana.TrackUsageParamsCommand{			EventName:      indiana.Ptr("image_generated"),			Quantity:       indiana.Ptr("1.25"),			IdempotencyKey: "merchant-event-123",		},	})	if err != nil {		log.Fatal(err)	}	for _, receipt := range usage.Receipts {		log.Println("usage accepted:", receipt.Accepted)	}}
  • A nil pointer omits an optional field; use indiana.Ptr(value) to send an explicit empty string, empty map or zero.
  • Response structs and JSON names are generated from the public contract, with Go initialisms such as CustomerID and RequestID. Quantities and amounts stay decimal strings.
  • indiana.LookupByID(id) and indiana.LookupByExternalUserID(id) build the lookup for GetCustomer and UpdateCustomer.

Methods

Every method takes a `context.Context` and returns a response pointer and an `error`.
MethodScopePermission
GetOrCreateCustomerExternalUserID or email; optional profile and fingerprint, existing profiles unchanged.customers:write
GetCustomerLookupByID or LookupByExternalUserID.customers:read
ListCustomersExplicit filters, offset and limit; inspect HasMore.customers:read
UpdateCustomerLookup, a retained RequestID and a partial Patch; change tags with TagChanges.customers:write
ReadHoldingsCustomer ID and optional Entity ID.entitlements:read
CheckEntitlementCustomer and a positive decimal-string Feature requirement.entitlements:read
TrackUsageCustomer and a command with exactly one of EventName or InternalFeatureID, plus a retained IdempotencyKey.credits:consume

Every method takes a `context.Context` and returns a response pointer and an `error`.

  • GetOrCreateCustomer

    Scope
    ExternalUserID or email; optional profile and fingerprint, existing profiles unchanged.
    Permission
    customers:write
  • GetCustomer

    Scope
    LookupByID or LookupByExternalUserID.
    Permission
    customers:read
  • ListCustomers

    Scope
    Explicit filters, offset and limit; inspect HasMore.
    Permission
    customers:read
  • UpdateCustomer

    Scope
    Lookup, a retained RequestID and a partial Patch; change tags with TagChanges.
    Permission
    customers:write
  • ReadHoldings

    Scope
    Customer ID and optional Entity ID.
    Permission
    entitlements:read
  • CheckEntitlement

    Scope
    Customer and a positive decimal-string Feature requirement.
    Permission
    entitlements:read
  • TrackUsage

    Scope
    Customer and a command with exactly one of EventName or InternalFeatureID, plus a retained IdempotencyKey.
    Permission
    credits:consume

Concurrency, timeouts and errors

Reuse one client across goroutines. Cancellation and deadlines use ordinary contexts. Config.Timeout bounds the whole request and body read (default 10 seconds, maximum 120). Close() refuses new calls and releases idle connections; an injected HTTPClient is cloned and its transport stays caller-owned. Ambient proxies, cookies and redirects are not used.

errors.goGo
package billing import (	"context"	"errors"	"log" 	indiana "tinker.cash/sdk/go") func readHoldings(ctx context.Context, client *indiana.Client, customerID string) error {	_, err := client.ReadHoldings(ctx, indiana.ReadHoldingsParams{CustomerID: customerID})	var sdkError *indiana.Error	if errors.As(err, &sdkError) {		log.Println(sdkError.Code, sdkError.Status, sdkError.RequestID, sdkError.Recovery)	}	if errors.Is(err, context.Canceled) {		// The caller cancelled. An accepted write may still have committed.	}	return err}

indiana.Error exposes Code, Status, RequestID, Retryable, Recovery, and optional Reason and RetryAfterSeconds. The SDK never retries; after an unknown result, replay usage events and Customer updates with the original IdempotencyKey/RequestID and input.

Other operations

The Go SDK covers seven operations: Customers, holdings, entitlement checks and usage. Call other server operations, such as sessions, payments, offers, invoices, balance management and Funnel decisions, directly over HTTP with the same Server Key, X-Indiana-Protocol: 0.6 and a JSON body, and handle failures by the error object's code and recovery.

sessions.goGo
package sessions import (	"bytes"	"context"	"encoding/json"	"fmt"	"net/http"	"os") // IssueCustomerToken calls an operation outside the SDK (sessions:create).func IssueCustomerToken(ctx context.Context, customerID string) (string, error) {	body, err := json.Marshal(map[string]string{"customerId": customerID})	if err != nil {		return "", err	}	request, err := http.NewRequestWithContext(ctx, http.MethodPost,		os.Getenv("INDIANA_API_URL")+"/api/v1/customer-sessions", bytes.NewReader(body))	if err != nil {		return "", err	}	request.Header.Set("Authorization", "Bearer "+os.Getenv("INDIANA_API_KEY"))	request.Header.Set("X-Indiana-Protocol", "0.6")	request.Header.Set("Content-Type", "application/json")	response, err := http.DefaultClient.Do(request)	if err != nil {		return "", err	}	defer response.Body.Close()	var result struct {		CustomerToken string `json:"customerToken"`		Error         *struct {			Code string `json:"code"`		} `json:"error"`	}	if err := json.NewDecoder(response.Body).Decode(&result); err != nil {		return "", err	}	if result.Error != nil {		return "", fmt.Errorf("indiana: %s", result.Error.Code)	}	return result.CustomerToken, nil}

Related: All operations·Request conventions