Go library for the Stripe API.

Go Stripe

GoDoc Build Status Coverage Status

The official Stripe Go client library.

Installation

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/v72"
    "github.com/stripe/stripe-go/v72/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/v72

Documentation

For a comprehensive list of examples, check out the API documentation.

See video demonstrations covering how to use the library.

For details on all the functionality in this library, see the GoDoc documentation.

Below are a few simple examples:

Customers

params := &stripe.CustomerParams{
	Description: stripe.String("Stripe Developer"),
	Email:       stripe.String("[email protected]"),
}

customer, err := customer.New(params)

PaymentIntents

params := &stripe.PaymentIntentListParams{
    Customer: stripe.String(customer.ID),
}

// set this so you can easily retry your request in case of a timeout
params.Params.IdempotencyKey = stripe.NewIdempotencyKey()

i := paymentintent.List(params)
for i.Next() {
	pi := i.PaymentIntent()
}

if err := i.Err(); err != nil {
	// handle
}

Events

i := event.List(nil)
for i.Next() {
	e := i.Event()

	// 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.PrevPreviousAttributes["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.

Authentication with Connect

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.

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")
// For any other kind of request
params := &stripe.CustomerParams{}
params.SetStripeAccount("acct_123")

To use a key, pass it to API's Init function:

import (
	"github.com/stripe/stripe-go/v72"
	"github.com/stripe/stripe-go/v72/client"
)

stripe := &client.API{}
stripe.Init("access_token", nil)

Google AppEngine

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/v72"
	"github.com/stripe/stripe-go/v72/client"
)

func handler(w http.ResponseWriter, r *http.Request) {
        c := appengine.NewContext(r)
        httpClient := urlfetch.Client(c)

        sc := stripeClient.New("sk_test_123", stripe.NewBackends(httpClient))

        params := &stripe.CustomerParams{
            Description: stripe.String("Stripe Developer"),
            Email:       stripe.String("[email protected]"),
        }
        customer, err := sc.Customers.New(params)
        if err != nil {
            fmt.Fprintf(w, "Could not create customer: %v", err)
        }
        fmt.Fprintf(w, "Customer created: %v", customer.ID)
}

Usage

While some resources may contain more/less APIs, the following pattern is applied throughout the library for a given $resource$:

Without a Client

If you're only dealing with a single key, you can simply import the packages required for the resources you're interacting with without the need to create a client.

import (
	"github.com/stripe/stripe-go/v72"
	"github.com/stripe/stripe-go/v72/$resource$"
)

// Setup
stripe.Key = "sk_key"

stripe.SetBackend("api", backend) // optional, useful for mocking

// Create
$resource$, err := $resource$.New(stripe.$Resource$Params)

// Get
$resource$, err := $resource$.Get(id, stripe.$Resource$Params)

// Update
$resource$, err := $resource$.Update(stripe.$Resource$Params)

// Delete
resourceDeleted, err := $resource$.Del(id, stripe.$Resource$Params)

// List
i := $resource$.List(stripe.$Resource$ListParams)
for i.Next() {
	$resource$ := i.$Resource$()
}

if err := i.Err(); err != nil {
	// handle
}

With a Client

If you're dealing with multiple keys, it is recommended you use client.API. This allows you to create as many clients as needed, each with their own individual key.

import (
	"github.com/stripe/stripe-go/v72"
	"github.com/stripe/stripe-go/v72/client"
)

// Setup
sc := &client.API{}
sc.Init("sk_key", nil) // the second parameter overrides the backends used if needed for mocking

// Create
$resource$, err := sc.$Resource$s.New(stripe.$Resource$Params)

// Get
$resource$, err := sc.$Resource$s.Get(id, stripe.$Resource$Params)

// Update
$resource$, err := sc.$Resource$s.Update(stripe.$Resource$Params)

// Delete
resourceDeleted, err := sc.$Resource$s.Del(id, stripe.$Resource$Params)

// List
i := sc.$Resource$s.List(stripe.$Resource$ListParams)
for i.Next() {
	resource := i.$Resource$()
}

if err := i.Err(); err != nil {
	// handle
}

Accessing the Last Response

Use LastResponse on any APIResource to look at the API response that generated the current object:

coupon, err := coupon.New(...)
requestID := coupon.LastResponse.RequestID

Similarly, for List operations, the last response is available on the list object attached to the iterator:

it := coupon.List(...)
for it.Next() {
    // Last response *NOT* on the individual iterator object
    it.Coupon().LastResponse // wrong

    // But rather on the list object, also accessible through the iterator
    requestID := it.CouponList().LastResponse.RequestID
}

See the definition of APIResponse for available fields.

Note that where API resources are nested in other API resources, only LastResponse on the top-level resource is set.

Automatic Retries

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 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/v72"
	"github.com/stripe/stripe-go/v72/client"
)

config := &stripe.BackendConfig{
    MaxNetworkRetries: stripe.Int64(0), // Zero retries
}

sc := &client.API{}
sc.Init("sk_key", &stripe.Backends{
    API:     stripe.GetBackendWithConfig(stripe.APIBackend, config),
    Uploads: stripe.GetBackendWithConfig(stripe.UploadsBackend, config),
})

coupon, err := sc.Coupons.New(...)

Configuring Logging

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 and Zap's SugaredLogger 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.

Expanding Objects

All expandable objects 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, _ := charge.Retrieve("ch_123", nil)

c.Customer.ID    // Only ID is populated
c.Customer.Name  // All other fields are always empty

//
// With expansion
//
p := &CustomerParams{}
p.AddExpand("customer")
c, _ := charge.Retrieve("ch_123", p)

c.Customer.ID    // ID is still available
c.Customer.Name  // Name is now also available (if it had a value)

Writing a Plugin

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.

Request latency telemetry

By default, the library sends request latency telemetry to Stripe. These numbers help Stripe improve the overall latency of its API for all users.

You can disable this behavior if you prefer:

config := &stripe.BackendConfig{
	EnableTelemetry: stripe.Bool(false),
}

Development

Pull requests from the community are welcome. If you submit one, please keep the following guidelines in mind:

  1. Code must be go fmt compliant.
  2. All types, structs and funcs should be documented.
  3. Ensure that make test succeeds.

Test

The test suite needs testify's require package to run:

github.com/stretchr/testify/require

Before running the tests, make sure to grab all of the package's dependencies:

go get -t -v

It also depends on stripe-mock, so make sure to fetch and run it from a background terminal (stripe-mock's README also contains instructions for installing via Homebrew and other methods):

go get -u github.com/stripe/stripe-mock
stripe-mock

Run all tests:

make test

Run tests for one package:

go test ./invoice

Run a single test:

go test ./invoice -run TestInvoiceGet

For any requests, bug or comments, please open an issue or submit a pull request.

Comments
  • Correct module name for Go module support

    Correct module name for Go module support

    Go modules takes the advise that you should change the import path on all breaking changes to a package and formalizes it as the import compatibility rule.

    As annoying as it is to update the major version in multiple places (tags, imports, the mod file), Go modules doesn't really work right unless you do. For example, right now if I add the following to my go.mod file:

    require github.com/stripe/stripe-go v52.0.0
    

    after I build it will be updated to something like the following because it doesn't think the version is correct:

    require github.com/stripe/stripe-go v0.0.0-20181029204007-b91932a178f5
    

    This change fixes the module name to include the v52 suffix and updates all imports so that an older version of the library doesn't get included in the v52 version.

    There are other ways to manage this aside from bumping the module version, eg. copying the entire package into a v52/ tree, or maintaining an internal base package and only overriding new things in a vXX tree, branches, etc. but those all seemed like even more of a pain to me.

    This is probably a pretty big decision, so this PR is more about getting discussion started about supporting Go modules more fully than anything else.

    It should be noted that old supported Go versions have been updated in a point release to understand this so it shouldn't break anything on other releases to change the module name.

    For more information on preparing a release see https://github.com/golang/go/wiki/Modules#releasing-modules-v2-or-higher

  • Rename all properties in the library to match the API reference

    Rename all properties in the library to match the API reference

    This should be the final PR to rework most of the library to:

    • match the naming in the API
    • split out resource and params structures
    • remove magic such as AmountZero or CouponEmpty and move all parameters to pointers

    We can't list all the changes one by one as those are extensive but here are the ones likely to impact most integrations:

    • All properties with the word url in it now have the same case such as BusinessURL.
    • All properties with the word four in it now use a digit such as DynamicLast4 or SSNLast4.
    • Renamed confusing properties such as Account on BankAccount becoming AccountNumber to avoid confusing with its Connect counterpart which is now named Account instead of AccountID.
    • Properties such as MonthAnchor or constants such as Month are now renamed to match the corresponding parameter/value in the API MonthlyAnchor and Monthly.
    • Meta and Live have been renamed to Metadata and Livemode on all classes
    • Values on List objects has been renamed to Data
    • Some classes have been renamed.
      • Owner is now AdditionalOwner,
      • Transaction is now BalanceTransaction with all constants and corresponding classes renamed to match this
      • references to Tx were also replaced by BalanceTransaction in classes, properties and constants
      • Fee and FeeRefund have been renamed to ApplicationFee and ApplicationFeeRefund along with all related classes, properties and constants.
      • Sub has been renamed to Subscription along with all related classes, properties and constants.
    • Card parameters have been renamed such as City becoming AddressCity and Month becoming ExpMonth.
    • Errors codes have been prefixed with ErrorCode such as ErrorCodeCardDeclined or ErrorCodeIncorrectZip.
    • Event properties are now named Object and PreviousAttributes and methods GetObjectValue() and GetPreviousValue().
    • Pagination properties have been renamed to StartingAfter, EndingBefore and HasMore.
    • AddMeta() has been renamed to AddMetadata(), Expand() to AddExpand()

    This replaces https://github.com/stripe/stripe-go/pull/459 and https://github.com/stripe/stripe-go/pull/507

  • Power test suite with stripe-mock + rework parameters with form

    Power test suite with stripe-mock + rework parameters with form

    Major changes:

    • Powers the test suite with stripe-mock so that we can turn tests back on in CI and improve its speed and reliability.
    • Every test suite has been entirely rewritten for consistency and better succinctness.
    • Introduce form package to make encoding parameters less buggy and reduce boilerplate involved.
    • Convert entire test suite over to testify's assertion package so that we're not maintaining a whole bunch of manually written assertions that tend to produce poor output (we've standardized on this package on internal Go projects too).

    Other changes:

    • Remove the duplicate Meta field from FeeRefundParams and TransferParams. Both these structs get a Meta through their Params member.

    ~~This is a WIP.~~

    Replaces #424, #440, and #442.

  • invalid character '<' looking for beginning of value

    invalid character '<' looking for beginning of value

    Hey,

    Some requests are failing with the following error:

    invalid character '<' looking for beginning of value

    I configured the number of retries to 3. Here's a timeline of what happened:

    On the Stripe dashboard:

    12:42:50 POST /charges ends with 200
    12:42:52 POST /charges ends with 409
    

    On my logs with LogLevel = 5:

    
    [app logs] 2018-08-01T10:42:53.489Z\",\"caller\":\"logger/logger.go:36\",\"message\":\"Stripe request ended with an error: invalid character '<' looking for beginning of value\", 
    
    [stripe-go logs] 
    "2018/08/01 10:42:53 Retry request https://api.stripe.com/v1/charges 1 time.",
    "2018/08/01 10:42:53 Stripe Response: \"{\\\\"id\\\": \\\"ch_*\\\",\
    "2018/08/01 10:42:53 Completed in 2.784733977s",
    "2018/08/01 10:42:52 Request failed with error: <nil>. Response: &{409....
    "2018/08/01 10:42:52 Requesting POST api.stripe.com/v1/charges"
    "2018/08/01 10:42:50 Requesting POST api.stripe.com/v1/charges"
    

    One of the two requests ended with a 409 and was retried and failed with the error in the title. As it does not appear on the dashboard, it seems it did not reach your servers.

    AFAIK, it should have been retried.

    Similar but maybe not related to #528

    go version: 1.10.1 stripe-go: 35.1.0

    Thanks!

  • Parse zero-val pointers

    Parse zero-val pointers

    If a boolean value is meant to be true by default, stripe-go uses a pointer to a bool, and uses nil to render no url parameter, which ends up being true to the stripe-api.

    Unfortunately, there was no ability to pass a pointer to a boolean of true. This attempts to fix it in a non-breaking, non-major change or refactor way.

    I made some smaller changes as well to assist in the readability (since I had to do a lot of that -- reading).

  • Charges sometimes requested with no POST body

    Charges sometimes requested with no POST body

    Go version: 1.12.5 Stripe Go version: v61.0.1

    Receive Stripe error code parameter_missing with failure Must provide source or customer. This happens sporadically, about 0.5% of the time (18 out of 3150 charges this morning). On looking at the Stripe developer logs dashboard I see that the request had no POST body at all.

    Screenshot at 2019-05-27 15-25-04

    Retrying the transaction with the exact same code works fine.

    Client code is pretty standard:

    	// Create the charge in Stripe
    	chargeParams := &stripe.ChargeParams{
    		Amount:      stripe.Int64(amount),
    		Currency:    stripe.String(string(currency)),
    		Description: stripe.String(description),
    		Customer:    stripe.String(customerToken),
    	}
    	chargeParams.AddExpand("balance_transaction")
    
    	if idempotencyKey != "" {
    		chargeParams.SetIdempotencyKey(idempotencyKey)
    	}
    
    	ch, err := charge.New(chargeParams)
    

    Can confirm that all values are set properly as they are logged just before creating the charge. And again, retrying seems to work.

  • Add Stripe client telemetry to request headers

    Add Stripe client telemetry to request headers

    Follows https://github.com/stripe/stripe-ruby/pull/696, https://github.com/stripe/stripe-php/pull/549, and https://github.com/stripe/stripe-python/pull/518 in adding telemetry metadata to request headers.

    The telemetry is disabled by default, and can be enabled per-client like so:

    backend := stripe.GetBackendWithConfig(
    	stripe.APIBackend,
    	&stripe.BackendConfig{
    		URL: "https://api.stripe.com/v1",
    		EnableTelemetry: true,
    	},
    )
    

    or globally by setting

    stripe.EnableTelemetry = true
    

    cc @dcarney-stripe @bobby-stripe

  • Update subscription with multiple plans

    Update subscription with multiple plans

    Hi Everybody,

    We are trying to update one-plan-subscription (plan id = "test2") with second plan and getting error: Cannot add multiple subscription items with the same plan PlanId.

    stripe-go params in Update function (/sub/client.go) seem to be OK:

    {...,"Plan":"",...,"Items":[{"...,"Quantity":0,"Plan":"test2","Deleted":false,...},{"...,"Quantity":0,"Plan":"addon1","Deleted":false,...}],...}

    Error returned by

    c.B.Call("POST", fmt.Sprintf("/subscriptions/%v", id), token, body, commonParams, sub)

    We can use https://stripe.com/docs/api#subscription_items multi-step create/update/delete endpoints theoretically, but prefer single subscription update because we need to change set of plans (1 or more) to another set of plans (1 or more) for existing subscription as one operation and it looks like it supposed to be possible according to https://stripe.com/docs/api#update_subscription or not?

    version: 22.1.0

    Thanks.

  • Add OAuth

    Add OAuth

    r? @remi-stripe

    Looking for some feedback:

    1. Is this PR too big?
    2. Is this a decent param passing approach? (I'm about 95% confident that I understand the reason for using pointers)
    3. Is stubbing out the server like this ok to test the oauth flow since oauth isnt supported by stripe-mock?

    Here's a sample echo server that uses this successfully:

    package main
    import (
      // "bytes"
      // "encoding/json"
      "github.com/foolin/goview/supports/echoview"
      "github.com/labstack/echo"
      "github.com/labstack/echo/middleware"
      "log"
      "net/http"
      "github.com/stripe/stripe-go"
      "github.com/stripe/stripe-go/oauth"
    )
    
    func main() {
      stripe.ClientID = "ca_123"
      stripe.Key = "sk_123"
    
      e := echo.New()
      e.Use(middleware.Logger())
      e.Use(middleware.Recover())
      e.Renderer = echoview.Default()
    
      e.GET("/", func(c echo.Context) error {
        return c.Render(http.StatusOK, "index", echo.Map{})
      })
    
      e.GET("/start", func(c echo.Context) error {
        // THEN...
        // client_id := "ca_123"
        // base := "https://connect.stripe.com"
        // path := "/oauth/authorize"
        // response_type := "code"
        // redirect_uri := "http://localhost:1323/callback"
        // query := fmt.Sprintf(
        //   "client_id=%s&response_type=%s&redirect_uri=%s",
        //   client_id,
        //   response_type,
        //   redirect_uri,
        // )
        // url := fmt.Sprintf("%s%s?%s", base, path, query)
        // NOW...
        url := oauth.AuthorizeURL(&stripe.AuthorizeURLParams{
          RedirectURI: stripe.String("http://localhost:1323/callback"),
        })
        return c.Redirect(http.StatusTemporaryRedirect, url)
      })
    
      e.GET("/callback", func(c echo.Context) error {
        // THEN...
        // client_secret := "sk_test_123"
        // code := c.QueryParam("code")
        // scope := c.QueryParam("scope")
        // state := c.QueryParam("state")
        // message := map[string]interface{}{
        //   "client_secret": client_secret,
        //   "grant_type": "authorization_code",
        //   "code": code,
        // }
        // bytesRepresentation, err := json.Marshal(message)
        // if err != nil {
        //   log.Fatalln(err)
        // }
        // resp, err := http.Post(
        //   "https://connect.stripe.com/oauth/token",
        //   "application/json",
        //   bytes.NewBuffer(bytesRepresentation),
        // )
        // if err != nil {
        //   log.Fatalln(err)
        // }
        // var result map[string]interface{}
        // json.NewDecoder(resp.Body).Decode(&result)
        // log.Println(result)
    
        token, err := oauth.New(&stripe.OAuthTokenParams{
          Code:      stripe.String(c.QueryParam("code")),
        })
        if err != nil {
          log.Fatalln(err)
        }
        return c.HTML(http.StatusOK, token.StripeUserID)
      })
      e.Logger.Fatal(e.Start(":1323"))
    }
    
  • Renaming all properties, structs and methods to match the API naming

    Renaming all properties, structs and methods to match the API naming

    This PR ensures that all properties in the library matches the official API. Names are not shortened anymore making it easier to associated a given parameter to its API counterpart.

    We can't list all the changes one by one as those are extensive but here are the ones likely to impact most integrations:

    • All properties with the word url in it now have the same case such as BusinessURL.
    • All properties with the word four in it now use a digit such as DynamicLast4 or SSNLast4.
    • Renamed confusing properties such as Account on BankAccount becoming AccountNumber to avoid confusing with its Connect counterpart which is now named Account instead of AccountID.
    • Properties such as MonthAnchor or constants such as Month are now renamed to match the corresponding parameter/value in the API MonthlyAnchor and Monthly.
    • Meta and Live have been renamed to Metadata and Livemode on all classes
    • Values on List objects has been renamed to Data
    • Some classes have been renamed.
      • Owner is now AdditionalOwner,
      • Transaction is now BalanceTransaction with all constants and corresponding classes renamed to match this
      • references to Tx were also replaced by BalanceTransaction in classes, properties and constants
      • Fee and FeeRefund have been renamed to ApplicationFee and ApplicationFeeRefund along with all related classes, properties and constants.
      • Sub has been renamed to Subscription along with all related classes, properties and constants.
    • Card parameters have been renamed such as City becoming AddressCity and Month becoming `ExpMonth.
    • Errors codes have been prefixed with ErrorCode such as ErrorCodeCardDeclined or ErrorCodeIncorrectZip.
    • Event properties are now named Object and PreviousAttributes and methods GetObjectValue() and GetPreviousValue().
    • Pagination properties have been renamed to StartingAfter, EndingBefore and HasMore.
    • AddMeta() has been renamed to AddMetadata(), Expand() to AddExpand()
  • App Engine:

    App Engine: "Call error 3: invalid security ticket"

    The documented approach for using this package on App Engine works for the first HTTP request, but never again. Specifically, the documentation says to call

    stripe.SetHTTPClient(urlfetch.Client(appengine.NewContext(r)))
    

    That creates and uses an HTTP client which is only valid for the life of the current HTTP request (r). On the next request, one calls stripe.SetHTTPClient again. That sets the default HTTP client but doesn't change the API backend, which still references the HTTP client from the first request.

    A second HTTP request might call something like customer.New(...) which calls stripe.GetBackend(stripe.APIBackend) which returns a backend referring to an HTTP client from the first request. Using that HTTP client gives an error like:

    Post https://api.stripe.com/v1/customers: Call error 3: invalid security ticket: 6e2752a700a25c35
    

    A better incantation for App Engine is something like:

    stripe.SetBackend(stripe.APIBackend, nil)
    stripe.SetHTTPClient(urlfetch.Client(appengine.NewContext(r)))
    

    I'd submit a pull request, but I'm not sure if this should be corrected in the documentation, in SetHTTPClient or in GetBackend

    Somewhat related, using a global HTTP client in App Engine is bound to cause trouble when simultaneous requests want to call Stripe APIs. Both goroutines will contend over stripe.httpClient and at most one goroutine can win. I wish I could recommend a good solution to that problem.

  • add missing verify with micro-deposits next action

    add missing verify with micro-deposits next action

    The next action type documented a verify_with_microdeposits value but did not have a constant for it.

    Add PaymentIntentNextActionTypeVerifyWithMicrodeposits as a constant for this value.

  • Adapt struct SubscriptionSchedulePhaseItemParams to incorporate empty string in order to disable the billing threshold

    Adapt struct SubscriptionSchedulePhaseItemParams to incorporate empty string in order to disable the billing threshold

    Is your feature request related to a problem? Please describe.

    I asked to support developers on Discord about how to disable the billing threshold from the SubscriptionSchedulePhaseItemParams struct. The documentation said you have to pass an empty string in order to disable it. I've tried to pass an empty SubscriptionSchedulePhaseItemParams struct or pass nil but it didn't work. Finally the solution they gave me is to set manually the empty string using the .AddExtra() method and pass it like this: phases[1][billing_thresholds]

    Describe the solution you'd like

    I would like to passing nil or the empty SubscriptionSchedulePhaseItemParams struct should disable the billing threshold.

    Describe alternatives you've considered

    No response

    Additional context

    No response

  • Improve support for unit testing

    Improve support for unit testing

    Is your feature request related to a problem? Please describe.

    Writing unit tests for code that uses this SDK is sometimes difficult. Some functions returns concrete types without any exported fields, which really limits the options for mocking.

    If I wanted to count the number of subscriptions I might create a simple service like this:

    package example
    
    import (
    	"fmt"
    
    	"github.com/stripe/stripe-go/v73/client"
    )
    
    type Service struct {
    	StripeClient *client.API
    }
    
    func (s Service) CountSubs() (int, error) {
    	itr := s.StripeClient.Subscriptions.List(nil)
    
    	var c int
    	for itr.Next() {
    		c++
    	}
    
    	if err := itr.Err(); err != nil {
    		return 0, fmt.Errorf("itr subs: %w", err)
    	}
    
    	return c, nil
    }
    

    To make it easier to test I can create an abstraction for the Stripe client like so:

    package example
    
    import (
    	"fmt"
    
    	"github.com/stripe/stripe-go/v73"
    	"github.com/stripe/stripe-go/v73/subscription"
    )
    
    type SubscriptionClient interface {
    	List(listParams *stripe.SubscriptionListParams) *subscription.Iter
    }
    
    type Service struct {
    	Subscriptions SubscriptionClient
    }
    
    func (s Service) CountSubs() (int, error) {
    	itr := s.Subscriptions.List(nil)
    
    	var c int
    	for itr.Next() {
    		c++
    	}
    
    	if err := itr.Err(); err != nil {
    		return 0, fmt.Errorf("itr subs: %w", err)
    	}
    
    	return c, nil
    }
    

    This will let me create a stub/mock of the client for use during testing:

    package example_test
    
    import (
    	"testing"
    
    	"example"
    
    	"github.com/stripe/stripe-go/v73"
    	"github.com/stripe/stripe-go/v73/subscription"
    )
    
    type SubscriptionClientStub struct{}
    
    func (s SubscriptionClientStub) List(listParams *stripe.SubscriptionListParams) *subscription.Iter {
    	return &subscription.Iter{}
    }
    
    func TestService_CountSubs(t *testing.T) {
    	t.Parallel()
    
    	var stub SubscriptionClientStub
    
    	unit := example.Service{
    		Subscriptions: &stub,
    	}
    
    	c, err := unit.CountSubs()
    	if err != nil {
    		t.Fatalf("counting subs failed: %s", err)
    	}
    	if c != 0 {
    		t.Fatalf("expected 0 subs but got: %d", c)
    	}
    }
    

    But the problem is that I have no control over the return type *subscription.Iter. Using the zero value results in a nil pointer error and since there is no exported fields I can't control the amount of subscriptions either.

    Describe the solution you'd like

    Functions and methods should return types that can be stubbed/mocked during testing.

    Eg. in this example replacing the returned *Iter type with an interface would solve the problem. Alternatively the Iter struct could expose some way to control the data source.

    Describe alternatives you've considered

    I know there's a stripe-mock library available but it wont let me control the output. Even if it did, it's a bit too complicated to set up for something this simple.

    Additional context

    If internal test files where in separate packages (eg. subscription_test) then these kind of problems would be more apparent at development time.

  • Use `stripe.Error` in function declarations?

    Use `stripe.Error` in function declarations?

    I'm new to Go, so apologies if this is a dumb idea.

    If the CRUD methods in paymentintent/client.go return a stripe.Error, shouldn't that be declared so that developers can see the stripe.Error help text when mousing over err in something like

    intent, err := client.PaymentIntents.New(args)
    

    (Whereas at the moment the generic error is used)

  • [Feature Request] Enable stripe event listener via sdk

    [Feature Request] Enable stripe event listener via sdk

    Can we call the equivalent of the stripe cli's stripe listen --forward-to localhost:8080 from the Go SDK, particularly if I could just supply the secret key, and not need to fuss with logging in.

    This would make it much easier to test in CI scenarios.

  • Distributed tracing and other context in logging

    Distributed tracing and other context in logging

    The current logging interface does not seem to allow callers to inject structured fields, such as trace ids, into the log lines. While custom loggers are acceptable, only global instances are acceptable, and the logging interface only passes Stripe's log messages as arguments.

    In my setup, I use context.Context to pass request ids into my logger, which in turn includes these request ids in the structured log lines that are written to stderr. Systems like OpenCensus/OpenTelemetry/OpenTracing also use context to pass correlation tokens through.

    It would be nice if the Stripe SDK had support for this, so that I could more easily correlate Stripe's logging with incoming requests. While it is possible to do this to a certain extent by overriding the http.Transaport, I'd like to take full advantage of the diagnostic logging that is already built into this library.

    I am curious if this has already been thought through, or if others have solutions. If not, it would be great to add support for this into the logging interfaces.


    The current API, for reference:

    https://github.com/stripe/stripe-go/blob/ebbff369b03d0cf6475352e7ae94b5684bcf0288/stripe.go#L181-L195

    https://github.com/stripe/stripe-go/blob/ebbff369b03d0cf6475352e7ae94b5684bcf0288/log.go#L124-L142

Go library for accessing the MyAnimeList API: http://myanimelist.net/modules.php?go=api

go-myanimelist go-myanimelist is a Go client library for accessing the MyAnimeList API. Project Status The MyAnimeList API has been stable for years a

Sep 28, 2022
go-whatsapp-rest-API is a Go library for the WhatsApp web which use Swagger as api interface

go-whatsapp-rest-API go-whatsapp-rest-API is a Go library for the WhatsApp web which use Swagger as api interface Multi-devices (MD) Support. This ver

Dec 15, 2022
Go client for the YNAB API. Unofficial. It covers 100% of the resources made available by the YNAB API.

YNAB API Go Library This is an UNOFFICIAL Go client for the YNAB API. It covers 100% of the resources made available by the YNAB API. Installation go

Oct 6, 2022
An API client for the Notion API implemented in Golang

An API client for the Notion API implemented in Golang

Dec 30, 2022
lambda-go-api-proxy makes it easy to port APIs written with Go frameworks such as Gin to AWS Lambda and Amazon API Gateway.

aws-lambda-go-api-proxy makes it easy to run Golang APIs written with frameworks such as Gin with AWS Lambda and Amazon API Gateway.

Jan 6, 2023
A API scanner written in GOLANG to scan files recursively and look for API keys and IDs.

GO FIND APIS _____ ____ ______ _____ _ _ _____ _____ _____ _____ / ____|/ __ \ | ____|_ _| \ | | __ \ /\ | __ \_

Oct 25, 2021
The NVD API is an unofficial Go wrapper around the NVD API.

NVD API The NVD API is an unofficial Go wrapper around the NVD API. Supports: CVE CPE How to use The following shows how to basically use the wrapper

Jan 7, 2023
A Wrapper Client for Google Spreadsheet API (Sheets API)

Senmai A Wrapper Client for Google Spreadsheet API (Sheets API) PREPARATION Service Account and Key File Create a service account on Google Cloud Plat

Nov 5, 2021
💾 Wolke API is the API behind Wolke image storage and processing aswell as user management

?? Wolke API Wolke API is the API behind Wolke image storage and processing aswell as user management Deploying To deploy Wolke Bot you'll need podman

Dec 21, 2021
Upcoming mobiles api (UpMob API)

upcoming_mobiles_api (UpMob API) UpMob API scraps 91mobiles.com to get devices i

Dec 21, 2021
Arweave-api - Arweave API implementation in golang

Arweave API Go implementation of the Arweave API Todo A list of endpoints that a

Jan 16, 2022
Api-product - A basic REST-ish API that allows you to perform CRUD operations for Products

Description A basic REST-ish API that allows you to perform CRUD operations for

Jan 3, 2022
Contact-api - API for websites I have designed that have to send unauthenticated email

contact https://aws.amazon.com/premiumsupport/knowledge-center/custom-headers-ap

Apr 11, 2022
Triangula-api-server - API server for processing images with Triangula

Triangula API server Minimalistic API server that calculates and serves artistic

Jan 10, 2022
Reservationbox-api - Reservationbox Api with golang
Reservationbox-api - Reservationbox Api with golang

reservationbox-api How to set up application Cloning git on this link : https://

Jan 30, 2022
Go api infra - Infrastructure for making api on golang so easy

Go Infra Api Infrastructre methods and types for make api simple Response abstra

Jun 18, 2022
Api-waf-example-cdk - Demo using sam to drive a CDK serverless api

CDK SAM Demo Demo using sam to drive a CDK serverless api Stack Setup go build -

Feb 5, 2022
A GoLang wrapper for Politics & War's API. Forego the hassle of accessing the API directly!

A GoLang wrapper for Politics & War's API. Forego the hassle of accessing the API directly!

Mar 5, 2022
An unofficial API based on Hasura API Reference.

An unofficial API based on Hasura API Reference.

Apr 14, 2022