Getting Started

This guide walks you through installing the Kard Go SDK, authenticating with the Kard API, and making your first request.

Prerequisites

  • Go 1.18+
  • KARD_CLIENT_ID and KARD_CLIENT_SECRET

Create a Client

Import and instantiate the client using your credentials.

This SDK supports two authentication methods:

OAuauth Client Credentials

client := client.NewClient(
option.WithToken("<YOUR_ACCESS_TOKEN>"),
)

Bearer Token Authentication

client := client.NewClient(
option.WithClientCredentials(
"<YOUR_CLIENT_ID>",
"<YOUR_CLIENT_SECRET>",
),
)

The client automatically handles authentication, retries, and timeouts.

Environments

This SDK allows you to configure different environments for API requests with the option.WithBaseURL option.

client := client.NewClient(
option.WithBaseURL(kard.Environments.Production),
)

Make Your First API Calls

1. Creating a User:

package example
import (
context "context"
kard "github.com/KardFinancial/kard-go-sdk"
client "github.com/KardFinancial/kard-go-sdk/client"
option "github.com/KardFinancial/kard-go-sdk/option"
)
func do() {
client := client.NewClient(
option.WithClientCredentials(
"<clientId>",
"<clientSecret>",
),
)
request := &kard.CreateUsersObject{
Data: []*kard.UserRequestDataUnion{
&kard.UserRequestDataUnion{
User: &kard.UserRequestData{
Id: "1234567890",
Attributes: &kard.UserRequestAttributes{
ZipCode: kard.String(
"11238",
),
EnrolledRewards: []kard.EnrolledRewardsType{
kard.EnrolledRewardsTypeCardlinked,
},
Email: kard.String(
"user@example.com",
),
HashedEmail: kard.String(
"a94a8fe5ccb19ba61c4c0873d391e987982fbbd3e2d8a5b76e45a1d4c4e2e3a1",
),
PhoneNumber: kard.String(
"+14155552671",
),
BirthYear: kard.String(
"1990",
),
HistoricalTransactionsSent: kard.Bool(
true,
),
},
},
},
},
}
client.Users.Create(
context.TODO(),
"organization-123",
request,
)
}

To enhance offer targeting and attribution, you can include a hashed email (HEM) when creating users. The SDK includes a built-in hem.GenerateHEM utility that normalizes and hashes email addresses:

package example
import (
context "context"
kard "github.com/KardFinancial/kard-go-sdk"
client "github.com/KardFinancial/kard-go-sdk/client"
hem "github.com/KardFinancial/kard-go-sdk/hem"
option "github.com/KardFinancial/kard-go-sdk/option"
)
func do() {
client := client.NewClient(
option.WithClientCredentials(
"<clientId>",
"<clientSecret>",
),
)
hashedEmail, err := hem.GenerateHEM("Jane.Doe+work@gmail.com")
if err != nil {
return
}
request := &kard.CreateUsersObject{
Data: []*kard.UserRequestDataUnion{
&kard.UserRequestDataUnion{
User: &kard.UserRequestData{
Id: "1234567890",
Attributes: &kard.UserRequestAttributes{
EnrolledRewards: []kard.EnrolledRewardsType{
kard.EnrolledRewardsTypeCardlinked,
},
HashedEmail: kard.String(
hashedEmail,
),
},
},
},
},
}
client.Users.Create(
context.TODO(),
"organization-123",
request,
)
}

The function normalizes the email before hashing (removes whitespace, lowercases, and handles Gmail-specific rules like dot and + suffix removal). It returns an error for invalid inputs.

2. Fetching Offers for User with Extended API:

package example
import (
context "context"
kard "github.com/KardFinancial/kard-go-sdk"
client "github.com/KardFinancial/kard-go-sdk/client"
option "github.com/KardFinancial/kard-go-sdk/option"
)
func do() {
client := client.NewClient(
option.WithClientCredentials(
"<clientId>",
"<clientSecret>",
),
)
request := &kard.GetOffersByUserRequest{
PageSize: kard.Int(
1,
),
FilterIsTargeted: kard.Bool(
true,
),
Sort: kard.String(
"-startDate",
),
SupportedComponents: []*kard.ComponentType{
kard.ComponentTypeShortDescription.Ptr(),
kard.ComponentTypeLongDescription.Ptr(),
kard.ComponentTypeCta.Ptr(),
kard.ComponentTypeTags.Ptr(),
kard.ComponentTypeDetailTags.Ptr(),
kard.ComponentTypeBaseReward.Ptr(),
},
}
client.Users.Rewards.Offers(
context.TODO(),
"organization-123",
"1234567890",
request,
)
}

3. Submitting Transaction for User:

package example
import (
context "context"
kard "github.com/KardFinancial/kard-go-sdk"
client "github.com/KardFinancial/kard-go-sdk/client"
option "github.com/KardFinancial/kard-go-sdk/option"
)
func do() {
client := client.NewClient(
option.WithClientCredentials(
"<clientId>",
"<clientSecret>",
),
)
request := &kard.CreateTransactionsObject{
Data: []*kard.TransactionsDataUnion{
&kard.TransactionsDataUnion{
Transaction: &kard.TransactionsData{
Id: "12345610",
Attributes: &kard.TransactionsAttributes{
UserId: "1234567890",
Amount: 1000,
Subtotal: kard.Int(
800,
),
Status: "APPROVED",
Currency: "USD",
Description: "ADVANCEAUTO",
AuthorizationDate: "2021-07-02T17:47:06Z",
PaymentType: kard.String(
"CARD",
),
Direction: "DEBIT",
Merchant: &kard.Merchant{
Id: "12345678901234567",
Name: "ADVANCEAUTO",
AddrStreet: kard.String(
"125 Main St",
),
AddrCity: kard.String(
"Philadelphia",
),
AddrState: kard.String(
"PA",
),
AddrZipcode: kard.String(
"19147",
),
AddrCountry: kard.String(
"United States",
),
Latitude: kard.String(
"37.9419429",
),
Longitude: kard.String(
"-73.1446869",
),
StoreId: kard.String(
"12345",
),
},
CardBin: "123456",
CardLastFour: "4321",
AuthorizationCode: kard.String(
"123456",
),
RetrievalReferenceNumber: kard.String(
"100804333919",
),
SystemTraceAuditNumber: kard.String(
"333828",
),
AcquirerReferenceNumber: kard.String(
"1234567890123456789012345678",
),
TransactionId: "12345611",
},
},
},
},
}
client.Transactions.Create(
context.TODO(),
"organization-123",
request,
)
}

All SDK methods return typed responses and typed errors.

Handling Errors

If an API request fails (4xx or 5xx), the SDK returns a structured error compatible with errors.Is and errors.As.

response, err := client.Users.Create(...)
if err != nil {
var apiError *core.APIError
if errors.As(err, apiError) {
// Do something with the API error ...
}
return err
}

Common Configuration Options

Configure Retries

Retries are enabled by default (max 2 attempts) with exponential backoff. The SDK retries on status codes 408, 429, and 5xx. Configure with option.WithMaxAttempts:

client := client.NewClient(
option.WithMaxAttempts(1),
)
response, err := client.Users.Create(
...,
option.WithMaxAttempts(1),
)

Set a Timeout

Use the standard context library to set a per-request timeout.

ctx, cancel := context.WithTimeout(ctx, time.Second)
defer cancel()
response, err := client.Users.Create(ctx, ...)

Access Raw HTTP Responses

To inspect headers or status codes, use WithRawResponse.

response, err := client.Users.WithRawResponse.Create(...)
if err != nil {
return err
}
fmt.Printf("Got response headers: %v", response.Header)
fmt.Printf("Got status code: %d", response.StatusCode)

Explicit Null

To send an explicit null through an optional parameter, use the setter methods on the request object; they flip a bit in explicitFields so the property is serialized rather than omitted.

type ExampleRequest struct {
// An optional string parameter.
Name *string `json:"name,omitempty" url:"-"`
// Private bitmask of fields set to an explicit value and therefore not to be omitted
explicitFields *big.Int `json:"-" url:"-"`
}
request := &ExampleRequest{}
request.SetName(nil)
response, err := client.Users.Create(ctx, request, ...)

Custom HTTP Client

A variety of request options are included to adapt the behavior of the library, which includes configuring authorization tokens, or providing your own instrumented *http.Client.

Providing your own *http.Client is recommended. Otherwise, the http.DefaultClient will be used, and your client will wait indefinitely for a response (unless the per-request, context-based timeout is used).

// Specify default options applied on every request.
client := client.NewClient(
option.WithToken("<YOUR_API_KEY>"),
option.WithHTTPClient(
&http.Client{
Timeout: 5 * time.Second,
},
),
)
// Specify options for an individual request.
response, err := client.Users.Create(
...,
option.WithToken("<YOUR_API_KEY>"),
)