go get tinker.cash/sdk/go@v0.6.0Version v0.6.0, Go 1.23+. Installs through Go's default module proxy and checksum database.
Related: Installation details
A goroutine-safe server client for Customers, holdings, entitlement checks and usage.
go get tinker.cash/sdk/go@v0.6.0Version v0.6.0, Go 1.23+. Installs through Go's default module proxy and checksum database.
Related: Installation details
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) }}nil pointer omits an optional field; use indiana.Ptr(value) to send an explicit empty string, empty map or zero.CustomerID and RequestID. Quantities and amounts stay decimal strings.indiana.LookupByID(id) and indiana.LookupByExternalUserID(id) build the lookup for GetCustomer and UpdateCustomer.| Method | Scope | Permission |
|---|---|---|
GetOrCreateCustomer | ExternalUserID or email; optional profile and fingerprint, existing profiles unchanged. | customers:write |
GetCustomer | LookupByID or LookupByExternalUserID. | customers:read |
ListCustomers | Explicit filters, offset and limit; inspect HasMore. | customers:read |
UpdateCustomer | Lookup, a retained RequestID and a partial Patch; change tags with TagChanges. | customers:write |
ReadHoldings | Customer ID and optional Entity ID. | entitlements:read |
CheckEntitlement | Customer and a positive decimal-string Feature requirement. | entitlements:read |
TrackUsage | Customer 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
ExternalUserID or email; optional profile and fingerprint, existing profiles unchanged.customers:writeGetCustomer
LookupByID or LookupByExternalUserID.customers:readListCustomers
HasMore.customers:readUpdateCustomer
RequestID and a partial Patch; change tags with TagChanges.customers:writeReadHoldings
entitlements:readCheckEntitlement
entitlements:readTrackUsage
EventName or InternalFeatureID, plus a retained IdempotencyKey.credits:consumeReuse 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.
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.
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.
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