[!TIP] Want to chat live with Stripe engineers? Join us on our Discord server.
The official [Stripe][stripe] Go client library.
Per our Language Version Support Policy, we support the 4 most recent Go versions at the time of release. Currently, that's Go 1.22+.
Read more and see the full schedule in the docs: https://docs.stripe.com/sdks/versioning?lang=go#stripe-sdk-language-version-support-policy
Make sure your project is using Go Modules (it will have a go.mod file in its
root if it already is):
go mod init
Then, reference stripe-go in a Go program with import:
import (
"github.com/stripe/stripe-go/v86"
"github.com/stripe/stripe-go/v86/customer"
)
Run any of the normal go commands (build/install/test). The Go
toolchain will resolve and fetch the stripe-go module automatically.
Alternatively, you can also explicitly go get the package into a project:
go get -u github.com/stripe/stripe-go/v86
For a comprehensive list of examples, check out the [API documentation][api-docs].
For details on all the functionality in this library, see the [Go documentation][goref].
Below are a few simple examples:
sc := stripe.NewClient(apiKey)
params := &stripe.CustomerCreateParams{
Description: stripe.String("Stripe Developer"),
Email: stripe.String("gostripe@stripe.com"),
PreferredLocales: stripe.StringSlice([]string{"en", "es"}),
}
c, err := sc.V1Customers.Create(context.TODO(), params)
sc := stripe.NewClient(apiKey)
params := &stripe.PaymentIntentListParams{
Customer: stripe.String(customer.ID),
}
for pi, err := range sc.V1PaymentIntents.List(context.TODO(), params) {
// handle err
// do something
}
sc := stripe.NewClient(apiKey)
for e, err := range sc.V1Events.List(context.TODO(), nil) {
// access event data via e.GetObjectValue("resource_name_based_on_type", "resource_property_name")
// alternatively you can access values via e.Data.Object["resource_name_based_on_type"].(map[string]interface{})["resource_property_name"]
// access previous attributes via e.GetPreviousValue("resource_name_based_on_type", "resource_property_name")
// alternatively you can access values via e.Data.PreviousAttributes["resource_name_based_on_type"].(map[string]interface{})["resource_property_name"]
}
Alternatively, you can use the event.Data.Raw property to unmarshal to the
appropriate struct.
There are two ways of authenticating requests when performing actions on behalf
of a connected account, one that uses the Stripe-Account header containing an
account's ID, and one that uses the account's keys. Usually the former is the
recommended approach. [See the documentation for more information][connect].
To use the Stripe-Account approach, use SetStripeAccount() on a ListParams
or Params class. For example:
// For a list request
listParams := &stripe.CustomerListParams{}
listParams.SetStripeAccount("acct_123")
To use a key, pass it into stripe.NewClient:
import (
"github.com/stripe/stripe-go/v86"
)
sc := stripe.NewClient("access_token")
If you're running the client in a Google AppEngine environment, you'll need to
create a per-request Stripe client since the http.DefaultClient is not
available. Here's a sample handler:
import (
"fmt"
"net/http"
"google.golang.org/appengine"
"google.golang.org/appengine/urlfetch"
"github.com/stripe/stripe-go/v86"
)
func handler(w http.ResponseWriter, r *http.Request) {
ctx := appengine.NewContext(r)
httpClient := urlfetch.Client(ctx)
backends := stripe.NewBackends(httpClient)
sc := stripe.NewClient("sk_test_123", stripe.WithBackends(backends))
params := &stripe.CustomerCreateParams{
Description: stripe.String("Stripe Developer"),
Email: stripe.String("gostripe@stripe.com"),
}
customer, err := sc.V1Customers.Create(ctx, params)
if err != nil {
fmt.Fprintf(w, "Could not create customer: %v", err)
return
}
fmt.Fprintf(w, "Customer created: %v", customer.ID)
}
While some resources may contain more/less APIs, the following pattern is
applied throughout the library for a given resource (like Customer).
The recommended pattern to access all Stripe resources is using stripe.Client. Below are some examples of how to use it to access the Customer resource.
import "github.com/stripe/stripe-go/v86"
// Setup
sc := stripe.NewClient("sk_key")
// To set backends, e.g. for testing, or to customize use this instead:
// sc := stripe.NewClient("sk_key", stripe.WithBackends(backends))
// Create
c, err := sc.V1Customers.Create(context.TODO(), &stripe.CustomerCreateParams{})
// Retrieve
c, err := sc.V1Customers.Retrieve(context.TODO(), id, &stripe.CustomerRetrieveParams{})
// Update
c, err := sc.V1Customers.Update(context.TODO(), id, &stripe.CustomerUpdateParams{})
// Delete
c, err := sc.V1Customers.Delete(context.TODO(), id, &stripe.CustomerDeleteParams{})
// List
for c, err := range sc.Customers.List(context.TODO(), &stripe.CustomerListParams{}) {
// handle err
// do something
}
stripe.Client vs legacy client.API patternWe introduced stripe.Client in v82.1 of the Go SDK. The legacy client pattern used prior to that version (using client.API) is still available to use but is marked as deprecated. Review the migration guide to use stripe.Client to help you move from the legacy pattern to stripe.Client.
The legacy pattern to access Stripe APIs is the "resource pattern" shown below. We plan to deprecate this pattern in a future release. Note also that Stripe's V2 APIs are not supported by this pattern.
import (
"github.com/stripe/stripe-go/v86"
"github.com/stripe/stripe-go/v86/customer"
)
// Setup
stripe.Key = "sk_key"
// Set backend (optional, useful for mocking)
// stripe.SetBackend("api", backend)
// Create
c, err := customer.New(&stripe.CustomerParams{})
// Get
c, err := customer.Get(id, &stripe.CustomerParams{})
// Update
c, err := customer.Update(id, &stripe.CustomerParams{})
// Delete
c, err := customer.Del(id, &stripe.CustomerParams{})
// List
i := customer.List(&stripe.CustomerListParams{})
for i.Next() {
c := i.Customer()
// do something
}
if err := i.Err(); err != nil {
// handle
}
Use LastResponse on any APIResource to look at the API response that
generated the current object:
coupon, err := sc.V1Coupons.Create(...)
requestID := coupon.LastResponse.RequestID
See the definition of [APIResponse][apiresponse] for available fields.
Note that where API resources are nested in other API resources, only
LastResponse on the top-level resource is set.
The library automatically retries requests on intermittent failures like on a
connection error, timeout, or on certain API responses like a status 409
Conflict. [Idempotency keys][idempotency-keys] are always added to requests to
make any such subsequent retries safe.
By default, it will perform up to two retries. That number can be configured
with MaxNetworkRetries:
import (
"github.com/stripe/stripe-go/v86"
)
config := &stripe.BackendConfig{
MaxNetworkRetries: stripe.Int64(0), // Zero retries
}
backends := &stripe.NewBackendWithConfig(config)
sc := stripe.NewClient("sk_key", stripe.WithBackends(backends))
coupon, err := sc.V1Coupons.Create(...)
By default, the library logs error messages only (which are sent to stderr).
Configure default logging using the global DefaultLeveledLogger variable:
stripe.DefaultLeveledLogger = &stripe.LeveledLogger{
Level: stripe.LevelInfo,
}
Or on a per-backend basis:
config := &stripe.BackendConfig{
LeveledLogger: &stripe.LeveledLogger{
Level: stripe.LevelInfo,
},
}
It's possible to use non-Stripe leveled loggers as well. Stripe expects loggers to comply to the following interface:
type LeveledLoggerInterface interface {
Debugf(format string, v ...interface{})
Errorf(format string, v ...interface{})
Infof(format string, v ...interface{})
Warnf(format string, v ...interface{})
}
Some loggers like [Logrus][logrus] and Zap's [SugaredLogger][zapsugaredlogger]
support this interface out-of-the-box so it's possible to set
DefaultLeveledLogger to a *logrus.Logger or *zap.SugaredLogger directly.
For others it may be necessary to write a thin shim layer to support them.
All [expandable objects][expandableobjects] in stripe-go take the form of a
full resource struct, but unless expansion is requested, only the ID field of
that struct is populated. Expansion is requested by calling AddExpand on
parameter structs. For example:
//
// *Without* expansion
//
c, _ := sc.V1Charges.Retrieve(context.TODO(), "ch_123", nil)
c.Customer.ID // Only ID is populated
c.Customer.Name // All other fields are always empty
//
// With expansion
//
p := &stripe.ChargeCreateParams{}
p.AddExpand("customer")
c, _ = sc.V1Charges.Retrieve(context.TODO(), "ch_123", p)
c.Customer.ID // ID is still available
c.Customer.Name // Name is now also available (if it had a value)
stripe-go is a typed library and it supports all public properties or parameters.
Stripe sometimes launches private preview features which introduce new properties or parameters that are not immediately public. These will not have typed accessors in the stripe-go library but can still be used.
To pass undocumented parameters to Stripe using stripe-go you need to use the AddExtra() method, as shown below:
params := &stripe.CustomerCreateParams{
Email: stripe.String("jenny.rosen@example.com")
}
params.AddExtra("secret_feature_enabled", "true")
params.AddExtra("secret_parameter[primary]","primary value")
params.AddExtra("secret_parameter[secondary]","secondary value")
customer, err := sc.V1Customer.Create(context.TODO(), params)
You can access undocumented properties returned by Stripe by querying the raw response JSON object. An example of this is shown below:
customer, _ = sc.V1Charges.Retrieve(context.TODO(), "cus_1234", nil);
var rawData map[string]interface{}
_ = json.Unmarshal(customer.LastResponse.RawJSON, &rawData)
secretFeatureEnabled, _ := string(rawData["secret_feature_enabled"].(bool))
secretParameter, ok := rawData["secret_parameter"].(map[string]interface{})
if ok {
primary := secretParameter["primary"].(string)
secondary := secretParameter["secondary"].(string)
}
For List and Search operations, you can access each resource's RawJSON as you iterate
for cust, err := range sc.V1Customers.List(context.TODO(), &stripe.CustomerListParams{}) {
if err != nil {
return err
}
customerJSON := cust.LastResponse.RawJSON
log.Printf("Customer JSON: %s", customerJSON) // {"id":"cus_123",...}
}
To access a private preview feature, you will likely need to use a special beta header. If you are using a public preview or private preview SDK version (those with a version v83.1.0-beta.1 or v83.1.0-alpha.1), you can use the stripe.AddBetaVersion function as described in Public Preview SDKs. With a release version like v83.1.0, you can still set a beta header on a per-request basis in your request params as follows:
params := &stripe.CustomerCreateParams{
...
Params: stripe.Params{
Headers: http.Header{
"Stripe-Version": []string{"2025-10-29.preview; beta_feature_1=v3; beta_feature_2=v1"},
},
},
}
Stripe can optionally sign the webhook events it sends to your endpoint, allowing you to validate that they were not sent by a third-party. You can read more about it here.
You can use stripe.GenerateTestSignedPayload to mock webhook events that come from Stripe:
payload := map[string]interface{}{
"id": "evt_test_webhook",
"object": "event",
"api_version": stripe.APIVersion,
}
testSecret := "whsec_test_secret"
payloadBytes, err := json.Marshal(payload)
signedPayload := stripe.GenerateTestSignedPayload(&webhook.UnsignedPayload{Payload: payloadBytes, Secret: testSecret})
event, err := stripe.ConstructEvent(signedPayload.Payload, signedPayload.Header, signedPayload.Secret)
if event.ID == payload["id"] {
// Do something with the mocked signed event
} else {
// Handle invalid event payload
}
If you're writing a plugin that uses the library, we'd appreciate it if you
identified using stripe.SetAppInfo:
stripe.SetAppInfo(&stripe.AppInfo{
Name: "MyAwesomePlugin",
URL: "https://myawesomeplugin.info",
Version: "1.2.34",
})
This information is passed along when the library makes calls to the Stripe
API. Note that while Name is always required, URL and Version are
optional.
By default, the library sends telemetry to Stripe regarding request latency and feature usage. These numbers help Stripe improve the overall latency of its API for all users, and improve
$ claude mcp add stripe-go \
-- python -m otcore.mcp_server <graph>