Repository: stripe/stripe-go
Pull request #1998 (2025-03-18 01:12:58)

Breaking changes to support V2
### Why?
<!-- Describe why this change is being made.  Briefly include history and context, high-level what this PR does, and what the world looks like afterward. -->
To give first-class support to V2 APIs in Go, we need to make two backwards incompatible changes in our Go SDK. Namely, we need to support
- A native `Amount` type in V2
- JSON-encoded payloads in V2

### What?
<!--
List out the key changes made in this PR, e.g.
- implements the antimatter particle trace in the nitronium microfilament drive
- updated tests -->
To support the above, this PR introduces these two breaking changes:
- Rename the `Amount` type in the `Balance` object to `BalanceAmount` (to avoid a name collision)
- Change the signature of the `CallRaw` method in the `Backend` interface to accept a `[]byte` instead of a `*form.Values` (to allow for passing in JSON-encoded payloads)
- There is also some additional plumbing work done in preparation for first-class V2 support in `stripe.go` that does not affect any existing V1 usage

## Changelog
- Renamed the `stripe.Amount` type in the `stripe.Balance` object to `stripe.BalanceAmount`
- Changed the signature of the `CallRaw` method in the `stripe.Backend` interface to accept a `[]byte` instead of `*form.Values` in its fourth argument. Call sites can safely replace a `*form.Values` argument `v` with `[]byte(v.Encode())` (`Encode` is `nil`-safe).


Patch:
diff --git a/account/client.go b/account/client.go
index f7de5d7f..c26bb3e0 100644
--- a/account/client.go
+++ b/account/client.go
@@ -156,7 +156,7 @@ func (c Client) List(listParams *stripe.AccountListParams) *Iter {
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.AccountList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/accounts", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/accounts", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/applepaydomain/client.go b/applepaydomain/client.go
index 431beec5..086a4ab9 100644
--- a/applepaydomain/client.go
+++ b/applepaydomain/client.go
@@ -69,7 +69,7 @@ func (c Client) List(listParams *stripe.ApplePayDomainListParams) *Iter {
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.ApplePayDomainList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/apple_pay/domains", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/apple_pay/domains", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/applicationfee/client.go b/applicationfee/client.go
index e5e4c429..10ed3226 100644
--- a/applicationfee/client.go
+++ b/applicationfee/client.go
@@ -43,7 +43,7 @@ func (c Client) List(listParams *stripe.ApplicationFeeListParams) *Iter {
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.ApplicationFeeList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/application_fees", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/application_fees", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/apps/secret/client.go b/apps/secret/client.go
index cc16379c..1701df00 100644
--- a/apps/secret/client.go
+++ b/apps/secret/client.go
@@ -68,7 +68,7 @@ func (c Client) List(listParams *stripe.AppsSecretListParams) *Iter {
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.AppsSecretList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/apps/secrets", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/apps/secrets", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/balance.go b/balance.go
index 80eba4ec..55f44305 100644
--- a/balance.go
+++ b/balance.go
@@ -31,7 +31,7 @@ func (p *BalanceParams) AddExpand(f string) {
 }
 
 // Available funds that you can transfer or pay out automatically by Stripe or explicitly through the [Transfers API](https://stripe.com/docs/api#transfers) or [Payouts API](https://stripe.com/docs/api#payouts). You can find the available balance for each currency and payment type in the `source_types` property.
-type Amount struct {
+type BalanceAmount struct {
 	// Balance amount.
 	Amount int64 `json:"amount"`
 	// Three-letter [ISO currency code](https://www.iso.org/iso-4217-currency-codes.html), in lowercase. Must be a [supported currency](https://stripe.com/docs/currencies).
@@ -59,7 +59,7 @@ type BalanceInstantAvailableNetAvailable struct {
 }
 type BalanceIssuing struct {
 	// Funds that are available for use.
-	Available []*Amount `json:"available"`
+	Available []*BalanceAmount `json:"available"`
 }
 
 // This is an object representing your Stripe balance. You can retrieve it to see
@@ -76,16 +76,16 @@ type BalanceIssuing struct {
 type Balance struct {
 	APIResource
 	// Available funds that you can transfer or pay out automatically by Stripe or explicitly through the [Transfers API](https://stripe.com/docs/api#transfers) or [Payouts API](https://stripe.com/docs/api#payouts). You can find the available balance for each currency and payment type in the `source_types` property.
-	Available []*Amount `json:"available"`
+	Available []*BalanceAmount `json:"available"`
 	// Funds held due to negative balances on connected accounts where [account.controller.requirement_collection](https://stripe.com/api/accounts/object#account_object-controller-requirement_collection) is `application`, which includes Custom accounts. You can find the connect reserve balance for each currency and payment type in the `source_types` property.
-	ConnectReserved []*Amount `json:"connect_reserved"`
+	ConnectReserved []*BalanceAmount `json:"connect_reserved"`
 	// Funds that you can pay out using Instant Payouts.
-	InstantAvailable []*Amount       `json:"instant_available"`
-	Issuing          *BalanceIssuing `json:"issuing"`
+	InstantAvailable []*BalanceAmount `json:"instant_available"`
+	Issuing          *BalanceIssuing  `json:"issuing"`
 	// Has the value `true` if the object exists in live mode or the value `false` if the object exists in test mode.
 	Livemode bool `json:"livemode"`
 	// String representing the object's type. Objects of the same type share the same value.
 	Object string `json:"object"`
 	// Funds that aren't available in the balance yet. You can find the pending balance for each currency and each payment type in the `source_types` property.
-	Pending []*Amount `json:"pending"`
+	Pending []*BalanceAmount `json:"pending"`
 }
diff --git a/balancetransaction/client.go b/balancetransaction/client.go
index 759519b7..5f18d99f 100644
--- a/balancetransaction/client.go
+++ b/balancetransaction/client.go
@@ -51,7 +51,7 @@ func (c Client) List(listParams *stripe.BalanceTransactionListParams) *Iter {
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.BalanceTransactionList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/balance_transactions", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/balance_transactions", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/bankaccount/client.go b/bankaccount/client.go
index 19162760..0fb03978 100644
--- a/bankaccount/client.go
+++ b/bankaccount/client.go
@@ -52,7 +52,7 @@ func (c Client) New(params *stripe.BankAccountParams) (*stripe.BankAccount, erro
 	// make an explicit call using a form and CallRaw instead of the standard
 	// Call (which takes a set of parameters).
 	bankaccount := &stripe.BankAccount{}
-	err := c.B.CallRaw(http.MethodPost, path, c.Key, body, &params.Params, bankaccount)
+	err := c.B.CallRaw(http.MethodPost, path, c.Key, []byte(body.Encode()), &params.Params, bankaccount)
 	return bankaccount, err
 }
 
@@ -175,7 +175,7 @@ func (c Client) List(listParams *stripe.BankAccountListParams) *Iter {
 				return nil, list, outerErr
 			}
 
-			err := c.B.CallRaw(http.MethodGet, path, c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, path, c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/billing/alert/client.go b/billing/alert/client.go
index e877217c..89672971 100644
--- a/billing/alert/client.go
+++ b/billing/alert/client.go
@@ -94,7 +94,7 @@ func (c Client) List(listParams *stripe.BillingAlertListParams) *Iter {
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.BillingAlertList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/billing/alerts", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/billing/alerts", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/billing/creditbalancetransaction/client.go b/billing/creditbalancetransaction/client.go
index 26672b04..5ec3ee0c 100644
--- a/billing/creditbalancetransaction/client.go
+++ b/billing/creditbalancetransaction/client.go
@@ -43,7 +43,7 @@ func (c Client) List(listParams *stripe.BillingCreditBalanceTransactionListParam
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.BillingCreditBalanceTransactionList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/billing/credit_balance_transactions", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/billing/credit_balance_transactions", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/billing/creditgrant/client.go b/billing/creditgrant/client.go
index 8a66a5b9..d2b47ed6 100644
--- a/billing/creditgrant/client.go
+++ b/billing/creditgrant/client.go
@@ -95,7 +95,7 @@ func (c Client) List(listParams *stripe.BillingCreditGrantListParams) *Iter {
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.BillingCreditGrantList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/billing/credit_grants", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/billing/credit_grants", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/billing/meter/client.go b/billing/meter/client.go
index 546abaac..21e70e92 100644
--- a/billing/meter/client.go
+++ b/billing/meter/client.go
@@ -94,7 +94,7 @@ func (c Client) List(listParams *stripe.BillingMeterListParams) *Iter {
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.BillingMeterList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/billing/meters", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/billing/meters", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/billing/metereventsummary/client.go b/billing/metereventsummary/client.go
index 90944d3a..eb700e48 100644
--- a/billing/metereventsummary/client.go
+++ b/billing/metereventsummary/client.go
@@ -32,7 +32,7 @@ func (c Client) List(listParams *stripe.BillingMeterEventSummaryListParams) *Ite
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.BillingMeterEventSummaryList{}
-			err := c.B.CallRaw(http.MethodGet, path, c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, path, c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/billingportal/configuration/client.go b/billingportal/configuration/client.go
index bbc9c600..c6e94dc2 100644
--- a/billingportal/configuration/client.go
+++ b/billingportal/configuration/client.go
@@ -69,7 +69,7 @@ func (c Client) List(listParams *stripe.BillingPortalConfigurationListParams) *I
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.BillingPortalConfigurationList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/billing_portal/configurations", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/billing_portal/configurations", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/capability/client.go b/capability/client.go
index 8c0e18e5..7ada133a 100644
--- a/capability/client.go
+++ b/capability/client.go
@@ -65,7 +65,7 @@ func (c Client) List(listParams *stripe.CapabilityListParams) *Iter {
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.CapabilityList{}
-			err := c.B.CallRaw(http.MethodGet, path, c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, path, c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/card/client.go b/card/client.go
index bfbf19d5..2b72dfe5 100644
--- a/card/client.go
+++ b/card/client.go
@@ -52,7 +52,7 @@ func (c Client) New(params *stripe.CardParams) (*stripe.Card, error) {
 	// make an explicit call using a form and CallRaw instead of the standard
 	// Call (which takes a set of parameters).
 	card := &stripe.Card{}
-	err := c.B.CallRaw(http.MethodPost, path, c.Key, body, &params.Params, card)
+	err := c.B.CallRaw(http.MethodPost, path, c.Key, []byte(body.Encode()), &params.Params, card)
 	return card, err
 }
 
@@ -161,7 +161,7 @@ func (c Client) List(listParams *stripe.CardListParams) *Iter {
 				return nil, list, outerErr
 			}
 
-			err := c.B.CallRaw(http.MethodGet, path, c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, path, c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/charge/client.go b/charge/client.go
index 2be30ba0..4c5f3280 100644
--- a/charge/client.go
+++ b/charge/client.go
@@ -93,7 +93,7 @@ func (c Client) List(listParams *stripe.ChargeListParams) *Iter {
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.ChargeList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/charges", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/charges", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
@@ -138,7 +138,7 @@ func (c Client) Search(params *stripe.ChargeSearchParams) *SearchIter {
 	return &SearchIter{
 		SearchIter: stripe.GetSearchIter(params, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.SearchContainer, error) {
 			list := &stripe.ChargeSearchResult{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/charges/search", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/charges/search", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/checkout/session/client.go b/checkout/session/client.go
index a45be7dc..fb283f4d 100644
--- a/checkout/session/client.go
+++ b/checkout/session/client.go
@@ -86,7 +86,7 @@ func (c Client) List(listParams *stripe.CheckoutSessionListParams) *Iter {
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.CheckoutSessionList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/checkout/sessions", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/checkout/sessions", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
@@ -128,7 +128,7 @@ func (c Client) ListLineItems(listParams *stripe.CheckoutSessionListLineItemsPar
 	return &LineItemIter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.LineItemList{}
-			err := c.B.CallRaw(http.MethodGet, path, c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, path, c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/client/api.go b/client/api.go
index f3bbcf46..cdd65456 100644
--- a/client/api.go
+++ b/client/api.go
@@ -424,7 +424,6 @@ type API struct {
 }
 
 func (a *API) Init(key string, backends *stripe.Backends) {
-
 	usage := []string{"stripe_client"}
 	if backends == nil {
 		backends = &stripe.Backends{
diff --git a/climate/order/client.go b/climate/order/client.go
index 77da6a6b..edf04175 100644
--- a/climate/order/client.go
+++ b/climate/order/client.go
@@ -91,7 +91,7 @@ func (c Client) List(listParams *stripe.ClimateOrderListParams) *Iter {
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.ClimateOrderList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/climate/orders", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/climate/orders", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/climate/product/client.go b/climate/product/client.go
index 6ed801eb..9522f78e 100644
--- a/climate/product/client.go
+++ b/climate/product/client.go
@@ -43,7 +43,7 @@ func (c Client) List(listParams *stripe.ClimateProductListParams) *Iter {
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.ClimateProductList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/climate/products", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/climate/products", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/climate/supplier/client.go b/climate/supplier/client.go
index c8893370..f8fd70ca 100644
--- a/climate/supplier/client.go
+++ b/climate/supplier/client.go
@@ -43,7 +43,7 @@ func (c Client) List(listParams *stripe.ClimateSupplierListParams) *Iter {
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.ClimateSupplierList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/climate/suppliers", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/climate/suppliers", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/countryspec/client.go b/countryspec/client.go
index 83581dff..c83346b0 100644
--- a/countryspec/client.go
+++ b/countryspec/client.go
@@ -43,7 +43,7 @@ func (c Client) List(listParams *stripe.CountrySpecListParams) *Iter {
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.CountrySpecList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/country_specs", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/country_specs", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/coupon/client.go b/coupon/client.go
index 2549bbe2..b668026a 100644
--- a/coupon/client.go
+++ b/coupon/client.go
@@ -85,7 +85,7 @@ func (c Client) List(listParams *stripe.CouponListParams) *Iter {
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.CouponList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/coupons", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/coupons", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/creditnote/client.go b/creditnote/client.go
index c4cfa6f7..def71cae 100644
--- a/creditnote/client.go
+++ b/creditnote/client.go
@@ -117,7 +117,7 @@ func (c Client) List(listParams *stripe.CreditNoteListParams) *Iter {
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.CreditNoteList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/credit_notes", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/credit_notes", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
@@ -158,7 +158,7 @@ func (c Client) ListLines(listParams *stripe.CreditNoteListLinesParams) *LineIte
 	return &LineItemIter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.CreditNoteLineItemList{}
-			err := c.B.CallRaw(http.MethodGet, path, c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, path, c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
@@ -180,7 +180,7 @@ func (c Client) PreviewLines(listParams *stripe.CreditNotePreviewLinesParams) *L
 	return &LineItemIter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.CreditNoteLineItemList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/credit_notes/preview/lines", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/credit_notes/preview/lines", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/customer/client.go b/customer/client.go
index 67387526..68a61844 100644
--- a/customer/client.go
+++ b/customer/client.go
@@ -130,7 +130,7 @@ func (c Client) List(listParams *stripe.CustomerListParams) *Iter {
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.CustomerList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/customers", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/customers", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
@@ -171,7 +171,7 @@ func (c Client) ListPaymentMethods(listParams *stripe.CustomerListPaymentMethods
 	return &PaymentMethodIter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.PaymentMethodList{}
-			err := c.B.CallRaw(http.MethodGet, path, c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, path, c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
@@ -216,7 +216,7 @@ func (c Client) Search(params *stripe.CustomerSearchParams) *SearchIter {
 	return &SearchIter{
 		SearchIter: stripe.GetSearchIter(params, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.SearchContainer, error) {
 			list := &stripe.CustomerSearchResult{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/customers/search", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/customers/search", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/customerbalancetransaction/client.go b/customerbalancetransaction/client.go
index dff1a5ac..b0e0e3a1 100644
--- a/customerbalancetransaction/client.go
+++ b/customerbalancetransaction/client.go
@@ -90,7 +90,7 @@ func (c Client) List(listParams *stripe.CustomerBalanceTransactionListParams) *I
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.CustomerBalanceTransactionList{}
-			err := c.B.CallRaw(http.MethodGet, path, c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, path, c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/customercashbalancetransaction/client.go b/customercashbalancetransaction/client.go
index 4331ed48..a9d3a322 100644
--- a/customercashbalancetransaction/client.go
+++ b/customercashbalancetransaction/client.go
@@ -49,7 +49,7 @@ func (c Client) List(listParams *stripe.CustomerCashBalanceTransactionListParams
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.CustomerCashBalanceTransactionList{}
-			err := c.B.CallRaw(http.MethodGet, path, c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, path, c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/dispute/client.go b/dispute/client.go
index f0d1e218..38068d78 100644
--- a/dispute/client.go
+++ b/dispute/client.go
@@ -77,7 +77,7 @@ func (c Client) List(listParams *stripe.DisputeListParams) *Iter {
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.DisputeList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/disputes", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/disputes", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/entitlements/activeentitlement/client.go b/entitlements/activeentitlement/client.go
index 4dc1d4aa..a50d919a 100644
--- a/entitlements/activeentitlement/client.go
+++ b/entitlements/activeentitlement/client.go
@@ -43,7 +43,7 @@ func (c Client) List(listParams *stripe.EntitlementsActiveEntitlementListParams)
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.EntitlementsActiveEntitlementList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/entitlements/active_entitlements", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/entitlements/active_entitlements", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/entitlements/feature/client.go b/entitlements/feature/client.go
index 03e367e5..00351b9a 100644
--- a/entitlements/feature/client.go
+++ b/entitlements/feature/client.go
@@ -69,7 +69,7 @@ func (c Client) List(listParams *stripe.EntitlementsFeatureListParams) *Iter {
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.EntitlementsFeatureList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/entitlements/features", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/entitlements/features", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/event/client.go b/event/client.go
index 614ba191..ecbe089b 100644
--- a/event/client.go
+++ b/event/client.go
@@ -43,7 +43,7 @@ func (c Client) List(listParams *stripe.EventListParams) *Iter {
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.EventList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/events", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/events", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/feerefund/client.go b/feerefund/client.go
index b8e2cb59..9c1c2235 100644
--- a/feerefund/client.go
+++ b/feerefund/client.go
@@ -113,7 +113,7 @@ func (c Client) List(listParams *stripe.FeeRefundListParams) *Iter {
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.FeeRefundList{}
-			err := c.B.CallRaw(http.MethodGet, path, c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, path, c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/file/client.go b/file/client.go
index e61244d5..3c8a7854 100644
--- a/file/client.go
+++ b/file/client.go
@@ -72,7 +72,7 @@ func (c Client) List(listParams *stripe.FileListParams) *Iter {
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.FileList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/files", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/files", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/filelink/client.go b/filelink/client.go
index 3a7dfb00..8c9e88d1 100644
--- a/filelink/client.go
+++ b/filelink/client.go
@@ -68,7 +68,7 @@ func (c Client) List(listParams *stripe.FileLinkListParams) *Iter {
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.FileLinkList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/file_links", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/file_links", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/financialconnections/account/client.go b/financialconnections/account/client.go
index 1569126c..5ab1bb22 100644
--- a/financialconnections/account/client.go
+++ b/financialconnections/account/client.go
@@ -99,7 +99,7 @@ func (c Client) List(listParams *stripe.FinancialConnectionsAccountListParams) *
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.FinancialConnectionsAccountList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/financial_connections/accounts", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/financial_connections/accounts", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
@@ -141,7 +141,7 @@ func (c Client) ListOwners(listParams *stripe.FinancialConnectionsAccountListOwn
 	return &OwnerIter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.FinancialConnectionsAccountOwnerList{}
-			err := c.B.CallRaw(http.MethodGet, path, c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, path, c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/financialconnections/transaction/client.go b/financialconnections/transaction/client.go
index 6e4d45d5..4a24cdf3 100644
--- a/financialconnections/transaction/client.go
+++ b/financialconnections/transaction/client.go
@@ -43,7 +43,7 @@ func (c Client) List(listParams *stripe.FinancialConnectionsTransactionListParam
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.FinancialConnectionsTransactionList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/financial_connections/transactions", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/financial_connections/transactions", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/form/form.go b/form/form.go
index e29e3766..a5ed4031 100644
--- a/form/form.go
+++ b/form/form.go
@@ -9,6 +9,7 @@ import (
 	"strconv"
 	"strings"
 	"sync"
+	"time"
 )
 
 const tagName = "form"
@@ -325,6 +326,14 @@ func intEncoder(values *Values, v reflect.Value, keyParts []string, encodeZero b
 	values.Add(FormatKey(keyParts), strconv.FormatInt(val, 10))
 }
 
+func timeEncoder(values *Values, v reflect.Value, keyParts []string, encodeZero bool, _ *formOptions) {
+	val := v.Interface().(time.Time)
+	if val.IsZero() && !encodeZero {
+		return
+	}
+	values.Add(FormatKey(keyParts), val.String())
+}
+
 func interfaceEncoder(values *Values, v reflect.Value, keyParts []string, encodeZero bool, _ *formOptions) {
 	// interfaceEncoder never encodes a `nil`, but it will pass through an
 	// `encodeZero` value into its chained encoder
@@ -461,6 +470,12 @@ func makeStructEncoder(t reflect.Type) *structEncoder {
 }
 
 func makeTypeEncoder(t reflect.Type) encoderFunc {
+	// For time.Time, we want to encode imediately it as a Unix timestamp,
+	// and don't want to inspect into it and encode it as a struct.
+	if t == reflect.TypeOf(time.Time{}) {
+		return timeEncoder
+	}
+
 	switch t.Kind() {
 	case reflect.Array, reflect.Slice:
 		return buildArrayOrSliceEncoder(t)
@@ -550,6 +565,9 @@ func (f *Values) Add(key, val string) {
 // Encode encodes the keys and values into “URL encoded” form
 // ("bar=baz&foo=quux").
 func (f *Values) Encode() string {
+	if f == nil {
+		return ""
+	}
 	var buf bytes.Buffer
 	for _, v := range f.values {
 		if buf.Len() > 0 {
diff --git a/forwarding/request/client.go b/forwarding/request/client.go
index e5560b0d..f21f9568 100644
--- a/forwarding/request/client.go
+++ b/forwarding/request/client.go
@@ -56,7 +56,7 @@ func (c Client) List(listParams *stripe.ForwardingRequestListParams) *Iter {
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.ForwardingRequestList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/forwarding/requests", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/forwarding/requests", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/identity/verificationreport/client.go b/identity/verificationreport/client.go
index e3b931df..264d913c 100644
--- a/identity/verificationreport/client.go
+++ b/identity/verificationreport/client.go
@@ -43,7 +43,7 @@ func (c Client) List(listParams *stripe.IdentityVerificationReportListParams) *I
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.IdentityVerificationReportList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/identity/verification_reports", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/identity/verification_reports", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/identity/verificationsession/client.go b/identity/verificationsession/client.go
index 149b4d69..f1f9240e 100644
--- a/identity/verificationsession/client.go
+++ b/identity/verificationsession/client.go
@@ -161,7 +161,7 @@ func (c Client) List(listParams *stripe.IdentityVerificationSessionListParams) *
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.IdentityVerificationSessionList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/identity/verification_sessions", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/identity/verification_sessions", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/invoice/client.go b/invoice/client.go
index 5aac964d..5ef5ee70 100644
--- a/invoice/client.go
+++ b/invoice/client.go
@@ -253,7 +253,7 @@ func (c Client) List(listParams *stripe.InvoiceListParams) *Iter {
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.InvoiceList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/invoices", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/invoices", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
@@ -294,7 +294,7 @@ func (c Client) ListLines(listParams *stripe.InvoiceListLinesParams) *LineItemIt
 	return &LineItemIter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.InvoiceLineItemList{}
-			err := c.B.CallRaw(http.MethodGet, path, c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, path, c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
@@ -316,7 +316,7 @@ func (c Client) UpcomingLines(listParams *stripe.InvoiceUpcomingLinesParams) *Li
 	return &LineItemIter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.InvoiceLineItemList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/invoices/upcoming/lines", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/invoices/upcoming/lines", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
@@ -361,7 +361,7 @@ func (c Client) Search(params *stripe.InvoiceSearchParams) *SearchIter {
 	return &SearchIter{
 		SearchIter: stripe.GetSearchIter(params, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.SearchContainer, error) {
 			list := &stripe.InvoiceSearchResult{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/invoices/search", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/invoices/search", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/invoiceitem/client.go b/invoiceitem/client.go
index 0711b7d4..941273db 100644
--- a/invoiceitem/client.go
+++ b/invoiceitem/client.go
@@ -82,7 +82,7 @@ func (c Client) List(listParams *stripe.InvoiceItemListParams) *Iter {
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.InvoiceItemList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/invoiceitems", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/invoiceitems", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/invoicerenderingtemplate/client.go b/invoicerenderingtemplate/client.go
index a8d4051c..90b78ab6 100644
--- a/invoicerenderingtemplate/client.go
+++ b/invoicerenderingtemplate/client.go
@@ -72,7 +72,7 @@ func (c Client) List(listParams *stripe.InvoiceRenderingTemplateListParams) *Ite
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.InvoiceRenderingTemplateList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/invoice_rendering_templates", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/invoice_rendering_templates", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/issuing/authorization/client.go b/issuing/authorization/client.go
index 2279ea31..c19d57ee 100644
--- a/issuing/authorization/client.go
+++ b/issuing/authorization/client.go
@@ -90,7 +90,7 @@ func (c Client) List(listParams *stripe.IssuingAuthorizationListParams) *Iter {
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.IssuingAuthorizationList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/issuing/authorizations", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/issuing/authorizations", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/issuing/card/client.go b/issuing/card/client.go
index 97fd7631..5ae757f3 100644
--- a/issuing/card/client.go
+++ b/issuing/card/client.go
@@ -68,7 +68,7 @@ func (c Client) List(listParams *stripe.IssuingCardListParams) *Iter {
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.IssuingCardList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/issuing/cards", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/issuing/cards", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/issuing/cardholder/client.go b/issuing/cardholder/client.go
index de4f23cf..52c1890c 100644
--- a/issuing/cardholder/client.go
+++ b/issuing/cardholder/client.go
@@ -70,7 +70,7 @@ func (c Client) List(listParams *stripe.IssuingCardholderListParams) *Iter {
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.IssuingCardholderList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/issuing/cardholders", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/issuing/cardholders", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/issuing/dispute/client.go b/issuing/dispute/client.go
index 1e778159..05b6c3d2 100644
--- a/issuing/dispute/client.go
+++ b/issuing/dispute/client.go
@@ -82,7 +82,7 @@ func (c Client) List(listParams *stripe.IssuingDisputeListParams) *Iter {
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.IssuingDisputeList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/issuing/disputes", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/issuing/disputes", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/issuing/personalizationdesign/client.go b/issuing/personalizationdesign/client.go
index dccd4c1c..56dfcf5a 100644
--- a/issuing/personalizationdesign/client.go
+++ b/issuing/personalizationdesign/client.go
@@ -69,7 +69,7 @@ func (c Client) List(listParams *stripe.IssuingPersonalizationDesignListParams)
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.IssuingPersonalizationDesignList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/issuing/personalization_designs", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/issuing/personalization_designs", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/issuing/physicalbundle/client.go b/issuing/physicalbundle/client.go
index 8d1b55de..be8c2824 100644
--- a/issuing/physicalbundle/client.go
+++ b/issuing/physicalbundle/client.go
@@ -43,7 +43,7 @@ func (c Client) List(listParams *stripe.IssuingPhysicalBundleListParams) *Iter {
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.IssuingPhysicalBundleList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/issuing/physical_bundles", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/issuing/physical_bundles", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/issuing/token/client.go b/issuing/token/client.go
index f33e8ebe..97e3d4ac 100644
--- a/issuing/token/client.go
+++ b/issuing/token/client.go
@@ -56,7 +56,7 @@ func (c Client) List(listParams *stripe.IssuingTokenListParams) *Iter {
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.IssuingTokenList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/issuing/tokens", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/issuing/tokens", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/issuing/transaction/client.go b/issuing/transaction/client.go
index 80d218c6..be35ab3a 100644
--- a/issuing/transaction/client.go
+++ b/issuing/transaction/client.go
@@ -56,7 +56,7 @@ func (c Client) List(listParams *stripe.IssuingTransactionListParams) *Iter {
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.IssuingTransactionList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/issuing/transactions", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/issuing/transactions", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/params.go b/params.go
index 5424c497..6e9c255f 100644
--- a/params.go
+++ b/params.go
@@ -30,7 +30,7 @@ const (
 // They're implemented as a custom type so that they can have their own
 // AppendTo implementation.
 type ExtraValues struct {
-	url.Values `form:"-"` // See custom AppendTo implementation
+	url.Values `form:"-" json:"-"` // See custom AppendTo implementation
 }
 
 // AppendTo implements custom form encoding for extra parameter values.
@@ -44,7 +44,7 @@ func (v ExtraValues) AppendTo(body *form.Values, keyParts []string) {
 
 // Filters is a structure that contains a collection of filters for list-related APIs.
 type Filters struct {
-	f []*filter `form:"-"` // See custom AppendTo implementation
+	f []*filter `form:"-" json:"-"` // See custom AppendTo implementation
 }
 
 // AddFilter adds a new filter with a given key, op and value.
@@ -177,6 +177,19 @@ type APIMode string
 var V1APIMode APIMode = "v1"
 var V2APIMode APIMode = "v2"
 
+func (m APIMode) contentType() string {
+	switch m {
+	case V1APIMode:
+		return "application/x-www-form-urlencoded"
+	case V2APIMode:
+		return "application/json"
+	default:
+		// The only way we can get here is if someone has mutated the APIMode
+		// variables, which would lead to unexpected behavior.
+		panic("unknown API mode")
+	}
+}
+
 // Params is the structure that contains the common properties
 // of any *Params structure.
 type Params struct {
@@ -188,27 +201,27 @@ type Params struct {
 	// guarantee whether the operation was or was not completed on Stripe's API
 	// servers. For certainty, you must either retry with the same idempotency
 	// key or query the state of the API.
-	Context context.Context `form:"-"`
+	Context context.Context `form:"-" json:"-"`
 
 	// Deprecated: please use Expand in the surrounding struct instead.
-	Expand []*string    `form:"expand"`
-	Extra  *ExtraValues `form:"*"`
+	Expand []*string    `form:"expand" json:"-"`
+	Extra  *ExtraValues `form:"*"  json:"-"`
 
 	// Headers may be used to provide extra header lines on the HTTP request.
-	Headers http.Header `form:"-"`
+	Headers http.Header `form:"-" json:"-"`
 
-	IdempotencyKey *string `form:"-"` // Passed as header
+	IdempotencyKey *string `form:"-" json:"-"` // Passed as header
 
 	// Deprecated: Please use Metadata in the surrounding struct instead.
-	Metadata map[string]string `form:"metadata"`
+	Metadata map[string]string `form:"metadata" json:"-"`
 
 	// StripeAccount may contain the ID of a connected account. By including
 	// this field, the request is made as if it originated from the connected
 	// account instead of under the account of the owner of the configured
 	// Stripe key.
-	StripeAccount *string `form:"-"` // Passed as header
+	StripeAccount *string `form:"-" json:"-"` // Passed as header
 
-	usage []string `form:"-"` // Tracked behaviors
+	usage []string `form:"-" json:"-"` // Tracked behaviors
 }
 
 // AddExpand on the Params embedded struct is deprecated.
diff --git a/paymentintent/client.go b/paymentintent/client.go
index 029d8826..91ff08c0 100644
--- a/paymentintent/client.go
+++ b/paymentintent/client.go
@@ -298,7 +298,7 @@ func (c Client) List(listParams *stripe.PaymentIntentListParams) *Iter {
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.PaymentIntentList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/payment_intents", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/payment_intents", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
@@ -343,7 +343,7 @@ func (c Client) Search(params *stripe.PaymentIntentSearchParams) *SearchIter {
 	return &SearchIter{
 		SearchIter: stripe.GetSearchIter(params, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.SearchContainer, error) {
 			list := &stripe.PaymentIntentSearchResult{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/payment_intents/search", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/payment_intents/search", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/paymentlink/client.go b/paymentlink/client.go
index b2c473a3..cf41d797 100644
--- a/paymentlink/client.go
+++ b/paymentlink/client.go
@@ -69,7 +69,7 @@ func (c Client) List(listParams *stripe.PaymentLinkListParams) *Iter {
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.PaymentLinkList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/payment_links", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/payment_links", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
@@ -111,7 +111,7 @@ func (c Client) ListLineItems(listParams *stripe.PaymentLinkListLineItemsParams)
 	return &LineItemIter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.LineItemList{}
-			err := c.B.CallRaw(http.MethodGet, path, c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, path, c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/paymentmethod/client.go b/paymentmethod/client.go
index 44d8ddaa..805ca714 100644
--- a/paymentmethod/client.go
+++ b/paymentmethod/client.go
@@ -123,7 +123,7 @@ func (c Client) List(listParams *stripe.PaymentMethodListParams) *Iter {
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.PaymentMethodList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/payment_methods", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/payment_methods", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/paymentmethodconfiguration/client.go b/paymentmethodconfiguration/client.go
index e96931f1..28271f01 100644
--- a/paymentmethodconfiguration/client.go
+++ b/paymentmethodconfiguration/client.go
@@ -71,7 +71,7 @@ func (c Client) List(listParams *stripe.PaymentMethodConfigurationListParams) *I
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.PaymentMethodConfigurationList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/payment_method_configurations", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/payment_method_configurations", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/paymentmethoddomain/client.go b/paymentmethoddomain/client.go
index 77347a45..65b703b5 100644
--- a/paymentmethoddomain/client.go
+++ b/paymentmethoddomain/client.go
@@ -92,7 +92,7 @@ func (c Client) List(listParams *stripe.PaymentMethodDomainListParams) *Iter {
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.PaymentMethodDomainList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/payment_method_domains", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/payment_method_domains", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/paymentsource/client.go b/paymentsource/client.go
index 599401ad..af971944 100644
--- a/paymentsource/client.go
+++ b/paymentsource/client.go
@@ -163,7 +163,7 @@ func (c Client) List(listParams *stripe.PaymentSourceListParams) *Iter {
 				return nil, list, outerErr
 			}
 
-			err := c.B.CallRaw(http.MethodGet, path, c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, path, c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/payout/client.go b/payout/client.go
index 139b9d1f..7b09178c 100644
--- a/payout/client.go
+++ b/payout/client.go
@@ -106,7 +106,7 @@ func (c Client) List(listParams *stripe.PayoutListParams) *Iter {
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.PayoutList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/payouts", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/payouts", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/person/client.go b/person/client.go
index e85f5fc2..43909350 100644
--- a/person/client.go
+++ b/person/client.go
@@ -93,7 +93,7 @@ func (c Client) List(listParams *stripe.PersonListParams) *Iter {
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.PersonList{}
-			err := c.B.CallRaw(http.MethodGet, path, c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, path, c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/plan/client.go b/plan/client.go
index 8259b948..3989969d 100644
--- a/plan/client.go
+++ b/plan/client.go
@@ -81,7 +81,7 @@ func (c Client) List(listParams *stripe.PlanListParams) *Iter {
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.PlanList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/plans", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/plans", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/price/client.go b/price/client.go
index 0f9114e6..faec1887 100644
--- a/price/client.go
+++ b/price/client.go
@@ -68,7 +68,7 @@ func (c Client) List(listParams *stripe.PriceListParams) *Iter {
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.PriceList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/prices", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/prices", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
@@ -113,7 +113,7 @@ func (c Client) Search(params *stripe.PriceSearchParams) *SearchIter {
 	return &SearchIter{
 		SearchIter: stripe.GetSearchIter(params, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.SearchContainer, error) {
 			list := &stripe.PriceSearchResult{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/prices/search", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/prices/search", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/product/client.go b/product/client.go
index 9227d483..e123aa22 100644
--- a/product/client.go
+++ b/product/client.go
@@ -81,7 +81,7 @@ func (c Client) List(listParams *stripe.ProductListParams) *Iter {
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.ProductList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/products", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/products", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
@@ -126,7 +126,7 @@ func (c Client) Search(params *stripe.ProductSearchParams) *SearchIter {
 	return &SearchIter{
 		SearchIter: stripe.GetSearchIter(params, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.SearchContainer, error) {
 			list := &stripe.ProductSearchResult{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/products/search", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/products/search", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/productfeature/client.go b/productfeature/client.go
index 5a889b74..c620608d 100644
--- a/productfeature/client.go
+++ b/productfeature/client.go
@@ -74,7 +74,7 @@ func (c Client) List(listParams *stripe.ProductFeatureListParams) *Iter {
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.ProductFeatureList{}
-			err := c.B.CallRaw(http.MethodGet, path, c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, path, c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/promotioncode/client.go b/promotioncode/client.go
index 251ef5d9..7217e76f 100644
--- a/promotioncode/client.go
+++ b/promotioncode/client.go
@@ -69,7 +69,7 @@ func (c Client) List(listParams *stripe.PromotionCodeListParams) *Iter {
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.PromotionCodeList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/promotion_codes", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/promotion_codes", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/quote/client.go b/quote/client.go
index 71d61de0..b72dbf8e 100644
--- a/quote/client.go
+++ b/quote/client.go
@@ -121,7 +121,7 @@ func (c Client) List(listParams *stripe.QuoteListParams) *Iter {
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.QuoteList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/quotes", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/quotes", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
@@ -163,7 +163,7 @@ func (c Client) ListComputedUpfrontLineItems(listParams *stripe.QuoteListCompute
 	return &LineItemIter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.LineItemList{}
-			err := c.B.CallRaw(http.MethodGet, path, c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, path, c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
@@ -204,7 +204,7 @@ func (c Client) ListLineItems(listParams *stripe.QuoteListLineItemsParams) *Line
 	return &LineItemIter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.LineItemList{}
-			err := c.B.CallRaw(http.MethodGet, path, c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, path, c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/radar/earlyfraudwarning/client.go b/radar/earlyfraudwarning/client.go
index 86a63312..ca19b52d 100644
--- a/radar/earlyfraudwarning/client.go
+++ b/radar/earlyfraudwarning/client.go
@@ -47,7 +47,7 @@ func (c Client) List(listParams *stripe.RadarEarlyFraudWarningListParams) *Iter
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.RadarEarlyFraudWarningList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/radar/early_fraud_warnings", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/radar/early_fraud_warnings", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/radar/valuelist/client.go b/radar/valuelist/client.go
index b596905b..60d33f0d 100644
--- a/radar/valuelist/client.go
+++ b/radar/valuelist/client.go
@@ -82,7 +82,7 @@ func (c Client) List(listParams *stripe.RadarValueListListParams) *Iter {
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.RadarValueListList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/radar/value_lists", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/radar/value_lists", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/radar/valuelistitem/client.go b/radar/valuelistitem/client.go
index a9225db1..232e5852 100644
--- a/radar/valuelistitem/client.go
+++ b/radar/valuelistitem/client.go
@@ -70,7 +70,7 @@ func (c Client) List(listParams *stripe.RadarValueListItemListParams) *Iter {
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.RadarValueListItemList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/radar/value_list_items", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/radar/value_list_items", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/refund/client.go b/refund/client.go
index c7bcfb16..17b71cc0 100644
--- a/refund/client.go
+++ b/refund/client.go
@@ -109,7 +109,7 @@ func (c Client) List(listParams *stripe.RefundListParams) *Iter {
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.RefundList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/refunds", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/refunds", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/reporting/reportrun/client.go b/reporting/reportrun/client.go
index 84bc18e4..92caa3be 100644
--- a/reporting/reportrun/client.go
+++ b/reporting/reportrun/client.go
@@ -56,7 +56,7 @@ func (c Client) List(listParams *stripe.ReportingReportRunListParams) *Iter {
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.ReportingReportRunList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/reporting/report_runs", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/reporting/report_runs", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/reporting/reporttype/client.go b/reporting/reporttype/client.go
index face8673..1d41cfc4 100644
--- a/reporting/reporttype/client.go
+++ b/reporting/reporttype/client.go
@@ -43,7 +43,7 @@ func (c Client) List(listParams *stripe.ReportingReportTypeListParams) *Iter {
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.ReportingReportTypeList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/reporting/report_types", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/reporting/report_types", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/review/client.go b/review/client.go
index 5b7170d5..e4119dac 100644
--- a/review/client.go
+++ b/review/client.go
@@ -56,7 +56,7 @@ func (c Client) List(listParams *stripe.ReviewListParams) *Iter {
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.ReviewList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/reviews", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/reviews", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/setupattempt/client.go b/setupattempt/client.go
index 1dee41c5..ed6b796c 100644
--- a/setupattempt/client.go
+++ b/setupattempt/client.go
@@ -31,7 +31,7 @@ func (c Client) List(listParams *stripe.SetupAttemptListParams) *Iter {
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.SetupAttemptList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/setup_attempts", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/setup_attempts", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/setupintent/client.go b/setupintent/client.go
index 58f37ec2..e43c5e66 100644
--- a/setupintent/client.go
+++ b/setupintent/client.go
@@ -152,7 +152,7 @@ func (c Client) List(listParams *stripe.SetupIntentListParams) *Iter {
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.SetupIntentList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/setup_intents", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/setup_intents", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/shippingrate/client.go b/shippingrate/client.go
index 42b4a13a..5bc011a0 100644
--- a/shippingrate/client.go
+++ b/shippingrate/client.go
@@ -69,7 +69,7 @@ func (c Client) List(listParams *stripe.ShippingRateListParams) *Iter {
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.ShippingRateList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/shipping_rates", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/shipping_rates", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/sigma/scheduledqueryrun/client.go b/sigma/scheduledqueryrun/client.go
index b172f5de..d28dd290 100644
--- a/sigma/scheduledqueryrun/client.go
+++ b/sigma/scheduledqueryrun/client.go
@@ -44,7 +44,7 @@ func (c Client) List(listParams *stripe.SigmaScheduledQueryRunListParams) *Iter
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.SigmaScheduledQueryRunList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/sigma/scheduled_query_runs", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/sigma/scheduled_query_runs", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/sourcetransaction/client.go b/sourcetransaction/client.go
index 54b3cecd..8d95eef2 100644
--- a/sourcetransaction/client.go
+++ b/sourcetransaction/client.go
@@ -41,7 +41,7 @@ func (c Client) List(listParams *stripe.SourceTransactionListParams) *Iter {
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.SourceTransactionList{}
-			err := c.B.CallRaw(http.MethodGet, path, c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, path, c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/stripe.go b/stripe.go
index b789c8db..ee169248 100644
--- a/stripe.go
+++ b/stripe.go
@@ -205,7 +205,7 @@ func (a *AppInfo) formatUserAgent() string {
 type Backend interface {
 	Call(method, path, key string, params ParamsContainer, v LastResponseSetter) error
 	CallStreaming(method, path, key string, params ParamsContainer, v StreamingLastResponseSetter) error
-	CallRaw(method, path, key string, body *form.Values, params *Params, v LastResponseSetter) error
+	CallRaw(method, path, key string, body []byte, params *Params, v LastResponseSetter) error
 	CallMultipart(method, path, key, boundary string, body *bytes.Buffer, params *Params, v LastResponseSetter) error
 	SetMaxNetworkRetries(maxNetworkRetries int64)
 }
@@ -359,10 +359,27 @@ func extractParams(params ParamsContainer) (*form.Values, *Params, error) {
 
 // Call is the Backend.Call implementation for invoking Stripe APIs.
 func (s *BackendImplementation) Call(method, path, key string, params ParamsContainer, v LastResponseSetter) error {
-	body, commonParams, err := extractParams(params)
+	bodyParams, commonParams, err := extractParams(params)
 	if err != nil {
 		return err
 	}
+	ver, err := extractVersion(path)
+	if err != nil {
+		return err
+	}
+
+	// For V1, all parameters are URL-encoded. For V2, for GET/DELETE requests,
+	// parameters are URL-encoded, and for POST requests, parameters are JSON-encoded.
+	var body []byte
+	if ver == V1APIMode || method != http.MethodPost {
+		body = []byte(bodyParams.Encode())
+	} else if params != nil && !(reflect.ValueOf(params).Kind() == reflect.Ptr && reflect.ValueOf(params).IsNil()) {
+		body, err = json.Marshal(params)
+		if err != nil {
+			return err
+		}
+	}
+
 	return s.CallRaw(method, path, key, body, commonParams, v)
 }
 
@@ -374,6 +391,11 @@ func (s *BackendImplementation) CallStreaming(method, path, key string, params P
 		return err
 	}
 
+	ver, err := extractVersion(path)
+	if err != nil {
+		return err
+	}
+
 	var body string
 	if formValues != nil && !formValues.Empty() {
 		body = formValues.Encode()
@@ -386,7 +408,7 @@ func (s *BackendImplementation) CallStreaming(method, path, key string, params P
 	}
 	bodyBuffer := bytes.NewBufferString(body)
 
-	req, err := s.NewRequest(method, path, key, "application/x-www-form-urlencoded", commonParams)
+	req, err := s.NewRequest(method, path, key, ver.contentType(), commonParams)
 	if err != nil {
 		return err
 	}
@@ -425,6 +447,20 @@ func (s *BackendImplementation) CallMultipart(method, path, key, boundary string
 	return nil
 }
 
+// extractVersion ensures the path starts with /v1, /v2, or contains /oauth
+// and returns the corresponding APIMode.
+func extractVersion(path string) (APIMode, error) {
+	if strings.HasPrefix(path, "/v1") {
+		return V1APIMode, nil
+	} else if strings.HasPrefix(path, "/v2") {
+		return V2APIMode, nil
+	} else if strings.Contains(path, "/oauth") {
+		return V1APIMode, nil
+	} else {
+		return APIMode(""), fmt.Errorf("unknown path prefix %s", path)
+	}
+}
+
 // the stripe API only accepts GET / POST / DELETE
 func validateMethod(method string) error {
 	if method != http.MethodPost && method != http.MethodGet && method != http.MethodDelete {
@@ -500,39 +536,36 @@ func (s *BackendImplementation) RawRequest(method, path, key, content string, pa
 }
 
 // CallRaw is the implementation for invoking Stripe APIs internally without a backend.
-func (s *BackendImplementation) CallRaw(method, path, key string, form *form.Values, params *Params, v LastResponseSetter) error {
-	var body string
-	if form != nil && !form.Empty() {
-		body = form.Encode()
+func (s *BackendImplementation) CallRaw(method, path, key string, body []byte, params *Params, v LastResponseSetter) error {
+	err := validateMethod(method)
+	if err != nil {
+		return err
+	}
 
-		err := validateMethod(method)
-		if err != nil {
-			return err
-		}
+	ver, err := extractVersion(path)
+	if err != nil {
+		return err
+	}
 
-		// On `GET` / `DELETE`, move the payload into the URL
-		if method != http.MethodPost {
-			path += "?" + body
-			body = ""
-		}
+	// On `GET` / `DELETE`, move the payload into the URL
+	if method != http.MethodPost {
+		path += "?" + string(body)
+		body = nil
 	}
-	bodyBuffer := bytes.NewBufferString(body)
 
-	req, err := s.NewRequest(method, path, key, "application/x-www-form-urlencoded", params)
+	req, err := s.NewRequest(method, path, key, ver.contentType(), params)
 	if err != nil {
 		return err
 	}
-
+	buf := bytes.NewBuffer(body)
 	responseSetter := metricsResponseSetter{
 		LastResponseSetter: v,
 		backend:            s,
 		params:             params,
 	}
-
-	if err := s.Do(req, bodyBuffer, &responseSetter); err != nil {
+	if err := s.Do(req, buf, &responseSetter); err != nil {
 		return err
 	}
-
 	return nil
 }
 
@@ -1622,7 +1655,7 @@ func (u *UsageBackend) Call(method, path, key string, params ParamsContainer, v
 	return u.B.Call(method, path, key, params, v)
 }
 
-func (u *UsageBackend) CallRaw(method, path, key string, body *form.Values, params *Params, v LastResponseSetter) error {
+func (u *UsageBackend) CallRaw(method, path, key string, body []byte, params *Params, v LastResponseSetter) error {
 	params.GetParams().InternalSetUsage(u.Usage)
 	return u.B.CallRaw(method, path, key, body, params, v)
 }
diff --git a/subscription/client.go b/subscription/client.go
index 24ad594b..8ecfb5ec 100644
--- a/subscription/client.go
+++ b/subscription/client.go
@@ -164,7 +164,7 @@ func (c Client) List(listParams *stripe.SubscriptionListParams) *Iter {
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.SubscriptionList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/subscriptions", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/subscriptions", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
@@ -209,7 +209,7 @@ func (c Client) Search(params *stripe.SubscriptionSearchParams) *SearchIter {
 	return &SearchIter{
 		SearchIter: stripe.GetSearchIter(params, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.SearchContainer, error) {
 			list := &stripe.SubscriptionSearchResult{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/subscriptions/search", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/subscriptions/search", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/subscriptionitem/client.go b/subscriptionitem/client.go
index 55345dd5..b62a714d 100644
--- a/subscriptionitem/client.go
+++ b/subscriptionitem/client.go
@@ -82,7 +82,7 @@ func (c Client) List(listParams *stripe.SubscriptionItemListParams) *Iter {
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.SubscriptionItemList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/subscription_items", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/subscription_items", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
@@ -128,7 +128,7 @@ func (c Client) UsageRecordSummaries(listParams *stripe.SubscriptionItemUsageRec
 	return &UsageRecordSummaryIter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.UsageRecordSummaryList{}
-			err := c.B.CallRaw(http.MethodGet, path, c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, path, c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/subscriptionschedule/client.go b/subscriptionschedule/client.go
index 66a14230..d38aad9a 100644
--- a/subscriptionschedule/client.go
+++ b/subscriptionschedule/client.go
@@ -95,7 +95,7 @@ func (c Client) List(listParams *stripe.SubscriptionScheduleListParams) *Iter {
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.SubscriptionScheduleList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/subscription_schedules", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/subscription_schedules", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/tax/calculation/client.go b/tax/calculation/client.go
index b0ddc139..f1073696 100644
--- a/tax/calculation/client.go
+++ b/tax/calculation/client.go
@@ -59,7 +59,7 @@ func (c Client) ListLineItems(listParams *stripe.TaxCalculationListLineItemsPara
 	return &LineItemIter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.TaxCalculationLineItemList{}
-			err := c.B.CallRaw(http.MethodGet, path, c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, path, c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/tax/registration/client.go b/tax/registration/client.go
index 07b98a93..62847e53 100644
--- a/tax/registration/client.go
+++ b/tax/registration/client.go
@@ -73,7 +73,7 @@ func (c Client) List(listParams *stripe.TaxRegistrationListParams) *Iter {
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.TaxRegistrationList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/tax/registrations", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/tax/registrations", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/tax/transaction/client.go b/tax/transaction/client.go
index b84e1882..45d8c84e 100644
--- a/tax/transaction/client.go
+++ b/tax/transaction/client.go
@@ -72,7 +72,7 @@ func (c Client) ListLineItems(listParams *stripe.TaxTransactionListLineItemsPara
 	return &LineItemIter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.TaxTransactionLineItemList{}
-			err := c.B.CallRaw(http.MethodGet, path, c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, path, c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/taxcode/client.go b/taxcode/client.go
index e2262a4f..95f9ec90 100644
--- a/taxcode/client.go
+++ b/taxcode/client.go
@@ -43,7 +43,7 @@ func (c Client) List(listParams *stripe.TaxCodeListParams) *Iter {
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.TaxCodeList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/tax_codes", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/tax_codes", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/taxid/client.go b/taxid/client.go
index a974d5ff..278a11bf 100644
--- a/taxid/client.go
+++ b/taxid/client.go
@@ -102,7 +102,7 @@ func (c Client) List(listParams *stripe.TaxIDListParams) *Iter {
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.TaxIDList{}
-			err := c.B.CallRaw(http.MethodGet, path, c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, path, c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/taxrate/client.go b/taxrate/client.go
index 638e4c28..4a9ebdb4 100644
--- a/taxrate/client.go
+++ b/taxrate/client.go
@@ -68,7 +68,7 @@ func (c Client) List(listParams *stripe.TaxRateListParams) *Iter {
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.TaxRateList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/tax_rates", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/tax_rates", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/terminal/configuration/client.go b/terminal/configuration/client.go
index 5b9ed813..1d307da9 100644
--- a/terminal/configuration/client.go
+++ b/terminal/configuration/client.go
@@ -82,7 +82,7 @@ func (c Client) List(listParams *stripe.TerminalConfigurationListParams) *Iter {
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.TerminalConfigurationList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/terminal/configurations", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/terminal/configurations", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/terminal/location/client.go b/terminal/location/client.go
index b6b415c7..f89f0161 100644
--- a/terminal/location/client.go
+++ b/terminal/location/client.go
@@ -84,7 +84,7 @@ func (c Client) List(listParams *stripe.TerminalLocationListParams) *Iter {
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.TerminalLocationList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/terminal/locations", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/terminal/locations", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/terminal/reader/client.go b/terminal/reader/client.go
index 837f09c7..df7e48fc 100644
--- a/terminal/reader/client.go
+++ b/terminal/reader/client.go
@@ -149,7 +149,7 @@ func (c Client) List(listParams *stripe.TerminalReaderListParams) *Iter {
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.TerminalReaderList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/terminal/readers", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/terminal/readers", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/topup/client.go b/topup/client.go
index bd4453be..c0e2c65e 100644
--- a/topup/client.go
+++ b/topup/client.go
@@ -81,7 +81,7 @@ func (c Client) List(listParams *stripe.TopupListParams) *Iter {
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.TopupList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/topups", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/topups", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/transfer/client.go b/transfer/client.go
index 51ba46cc..fd031f4f 100644
--- a/transfer/client.go
+++ b/transfer/client.go
@@ -72,7 +72,7 @@ func (c Client) List(listParams *stripe.TransferListParams) *Iter {
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.TransferList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/transfers", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/transfers", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/transferreversal/client.go b/transferreversal/client.go
index c48970cb..e894b2eb 100644
--- a/transferreversal/client.go
+++ b/transferreversal/client.go
@@ -91,7 +91,7 @@ func (c Client) List(listParams *stripe.TransferReversalListParams) *Iter {
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.TransferReversalList{}
-			err := c.B.CallRaw(http.MethodGet, path, c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, path, c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/treasury/creditreversal/client.go b/treasury/creditreversal/client.go
index 0c865f61..fa8591ee 100644
--- a/treasury/creditreversal/client.go
+++ b/treasury/creditreversal/client.go
@@ -56,7 +56,7 @@ func (c Client) List(listParams *stripe.TreasuryCreditReversalListParams) *Iter
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.TreasuryCreditReversalList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/treasury/credit_reversals", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/treasury/credit_reversals", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/treasury/debitreversal/client.go b/treasury/debitreversal/client.go
index 36709154..af69866d 100644
--- a/treasury/debitreversal/client.go
+++ b/treasury/debitreversal/client.go
@@ -56,7 +56,7 @@ func (c Client) List(listParams *stripe.TreasuryDebitReversalListParams) *Iter {
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.TreasuryDebitReversalList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/treasury/debit_reversals", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/treasury/debit_reversals", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/treasury/financialaccount/client.go b/treasury/financialaccount/client.go
index c80661da..6698c817 100644
--- a/treasury/financialaccount/client.go
+++ b/treasury/financialaccount/client.go
@@ -111,7 +111,7 @@ func (c Client) List(listParams *stripe.TreasuryFinancialAccountListParams) *Ite
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.TreasuryFinancialAccountList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/treasury/financial_accounts", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/treasury/financial_accounts", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/treasury/inboundtransfer/client.go b/treasury/inboundtransfer/client.go
index ec996abd..99483983 100644
--- a/treasury/inboundtransfer/client.go
+++ b/treasury/inboundtransfer/client.go
@@ -69,7 +69,7 @@ func (c Client) List(listParams *stripe.TreasuryInboundTransferListParams) *Iter
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.TreasuryInboundTransferList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/treasury/inbound_transfers", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/treasury/inbound_transfers", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/treasury/outboundpayment/client.go b/treasury/outboundpayment/client.go
index ef3beb5f..6cd7dd36 100644
--- a/treasury/outboundpayment/client.go
+++ b/treasury/outboundpayment/client.go
@@ -69,7 +69,7 @@ func (c Client) List(listParams *stripe.TreasuryOutboundPaymentListParams) *Iter
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.TreasuryOutboundPaymentList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/treasury/outbound_payments", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/treasury/outbound_payments", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/treasury/outboundtransfer/client.go b/treasury/outboundtransfer/client.go
index 55f99aac..e044c6ab 100644
--- a/treasury/outboundtransfer/client.go
+++ b/treasury/outboundtransfer/client.go
@@ -69,7 +69,7 @@ func (c Client) List(listParams *stripe.TreasuryOutboundTransferListParams) *Ite
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.TreasuryOutboundTransferList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/treasury/outbound_transfers", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/treasury/outbound_transfers", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/treasury/receivedcredit/client.go b/treasury/receivedcredit/client.go
index 54dffa9b..5322c8a0 100644
--- a/treasury/receivedcredit/client.go
+++ b/treasury/receivedcredit/client.go
@@ -43,7 +43,7 @@ func (c Client) List(listParams *stripe.TreasuryReceivedCreditListParams) *Iter
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.TreasuryReceivedCreditList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/treasury/received_credits", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/treasury/received_credits", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/treasury/receiveddebit/client.go b/treasury/receiveddebit/client.go
index a5adc153..3c72d97e 100644
--- a/treasury/receiveddebit/client.go
+++ b/treasury/receiveddebit/client.go
@@ -43,7 +43,7 @@ func (c Client) List(listParams *stripe.TreasuryReceivedDebitListParams) *Iter {
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.TreasuryReceivedDebitList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/treasury/received_debits", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/treasury/received_debits", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/treasury/transaction/client.go b/treasury/transaction/client.go
index 4c170683..d41d79f1 100644
--- a/treasury/transaction/client.go
+++ b/treasury/transaction/client.go
@@ -43,7 +43,7 @@ func (c Client) List(listParams *stripe.TreasuryTransactionListParams) *Iter {
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.TreasuryTransactionList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/treasury/transactions", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/treasury/transactions", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/treasury/transactionentry/client.go b/treasury/transactionentry/client.go
index 4b7bcc63..4c9f3f4a 100644
--- a/treasury/transactionentry/client.go
+++ b/treasury/transactionentry/client.go
@@ -43,7 +43,7 @@ func (c Client) List(listParams *stripe.TreasuryTransactionEntryListParams) *Ite
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.TreasuryTransactionEntryList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/treasury/transaction_entries", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/treasury/transaction_entries", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/usagerecordsummary/client.go b/usagerecordsummary/client.go
index 680f1276..b4e1b119 100644
--- a/usagerecordsummary/client.go
+++ b/usagerecordsummary/client.go
@@ -37,7 +37,7 @@ func (c Client) List(listParams *stripe.UsageRecordSummaryListParams) *Iter {
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.UsageRecordSummaryList{}
-			err := c.B.CallRaw(http.MethodGet, path, c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, path, c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/webhookendpoint/client.go b/webhookendpoint/client.go
index e956a359..bba6c83a 100644
--- a/webhookendpoint/client.go
+++ b/webhookendpoint/client.go
@@ -82,7 +82,7 @@ func (c Client) List(listParams *stripe.WebhookEndpointListParams) *Iter {
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.WebhookEndpointList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/webhook_endpoints", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/webhook_endpoints", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {


Test patch:
diff --git a/file/client_test.go b/file/client_test.go
index d8fc9f68..23df29e6 100644
--- a/file/client_test.go
+++ b/file/client_test.go
@@ -18,7 +18,6 @@ import (
 
 	assert "github.com/stretchr/testify/require"
 	stripe "github.com/stripe/stripe-go/v81"
-	"github.com/stripe/stripe-go/v81/form"
 	_ "github.com/stripe/stripe-go/v81/testing"
 )
 
@@ -53,7 +52,7 @@ func (b *testBackend) Call(method, path, key string, params stripe.ParamsContain
 func (b *testBackend) CallStreaming(method, path, key string, params stripe.ParamsContainer, v stripe.StreamingLastResponseSetter) error {
 	return nil
 }
-func (b *testBackend) CallRaw(method, path, key string, body *form.Values, params *stripe.Params, v stripe.LastResponseSetter) error {
+func (b *testBackend) CallRaw(method, path, key string, body []byte, params *stripe.Params, v stripe.LastResponseSetter) error {
 	return nil
 }
 func (b *testBackend) CallMultipart(method, path, key, boundary string, body *bytes.Buffer, params *stripe.Params, v stripe.LastResponseSetter) error {
diff --git a/search_iter_test.go b/search_iter_test.go
index 97d1cf30..e8b9eabd 100644
--- a/search_iter_test.go
+++ b/search_iter_test.go
@@ -169,7 +169,7 @@ func (c Client) Search(params *SearchParams) *TestSearchIter {
 	return &TestSearchIter{
 		SearchIter: GetSearchIter(params, func(p *Params, b *form.Values) ([]interface{}, SearchContainer, error) {
 			list := &TestSearchResult{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/something/search", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/something/search", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {
diff --git a/stripe_test.go b/stripe_test.go
index 537674e9..c15ad11b 100644
--- a/stripe_test.go
+++ b/stripe_test.go
@@ -464,7 +464,7 @@ func TestCall_TelemetryDisabled(t *testing.T) {
 	// metrics aren't being sent, we need to fire off two requests in sequence.
 	for i := 0; i < 2; i++ {
 		var response testServerResponse
-		err := backend.Call("get", "/hello", "sk_test_xyz", nil, &response)
+		err := backend.Call(http.MethodGet, "/v1/hello", "sk_test_xyz", nil, &response)
 
 		assert.NoError(t, err)
 		assert.Equal(t, message, response.Message)
@@ -549,7 +549,7 @@ func TestCall_TelemetryEnabled(t *testing.T) {
 	params.InternalSetUsage([]string{"llama", "bufo"})
 	for i := 0; i < 2; i++ {
 		var response testServerResponse
-		err := backend.Call("GET", "/hello", "sk_test_xyz", params, &response)
+		err := backend.Call(http.MethodGet, "/v1/hello", "sk_test_xyz", params, &response)
 
 		assert.NoError(t, err)
 		assert.Equal(t, message, response.Message)
@@ -563,7 +563,7 @@ func TestCall_TelemetryEnabled(t *testing.T) {
 // that our logic for buffering requestMetrics when EnableTelemetry = true does
 // not trigger any data races. This test should pass when the -race flag is
 // passed to `go test`.
-func TestDo_TelemetryEnabledNoDataRace(t *testing.T) {
+func TestCall_TelemetryEnabledNoDataRace(t *testing.T) {
 	type testServerResponse struct {
 		APIResource
 		Message string `json:"message"`
@@ -602,7 +602,7 @@ func TestDo_TelemetryEnabledNoDataRace(t *testing.T) {
 	for i := 0; i < times; i++ {
 		go func() {
 			var response testServerResponse
-			err := backend.Call("get", "/hello", "sk_test_xyz", nil, &response)
+			err := backend.Call(http.MethodGet, "/v1/hello", "sk_test_xyz", nil, &response)
 
 			assert.NoError(t, err)
 			assert.Equal(t, message, response.Message)
@@ -618,6 +618,151 @@ func TestDo_TelemetryEnabledNoDataRace(t *testing.T) {
 	assert.Equal(t, int32(times), requestNum)
 }
 
+// Test that a GET to a v2 endpoint works and is sent with
+// the correct query parameters
+func TestCall_V2PathGet(t *testing.T) {
+	type testServerResponse struct {
+		APIResource
+		Message string `json:"message"`
+	}
+
+	message := "Hello, client."
+
+	testServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		assert.Equal(t, r.Method, http.MethodGet)
+		assert.Equal(t, r.URL.Path, "/v2/hello")
+		assert.Equal(t, r.URL.Query().Get("foo"), "bar")
+
+		data, err := json.Marshal(testServerResponse{Message: message})
+		assert.NoError(t, err)
+
+		_, err = w.Write(data)
+		assert.NoError(t, err)
+	}))
+	defer testServer.Close()
+
+	backend := GetBackendWithConfig(
+		APIBackend,
+		&BackendConfig{
+			EnableTelemetry:   Bool(true),
+			LeveledLogger:     debugLeveledLogger,
+			MaxNetworkRetries: Int64(0),
+			URL:               String(testServer.URL),
+		},
+	)
+
+	type myCreateParams struct {
+		Params `form:"*"`
+		Foo    string `form:"foo" json:"foo"`
+	}
+	params := &myCreateParams{
+		Foo: "bar",
+	}
+
+	var response testServerResponse
+	err := backend.Call(http.MethodGet, "/v2/hello", "sk_test_xyz", params, &response)
+
+	assert.NoError(t, err)
+	assert.Equal(t, message, response.Message)
+}
+
+// Test that a POST to a v2 endpoint works and is sent with
+// the correct JSON contentType
+func TestCall_V2PathPost(t *testing.T) {
+	type testServerResponse struct {
+		APIResource
+		Message string `json:"message"`
+	}
+
+	message := "Hello, client."
+
+	testServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		assert.Equal(t, r.Method, http.MethodPost)
+		assert.Equal(t, r.URL.Path, "/v2/hello")
+		assert.Equal(t, r.Header.Get("Content-Type"), "application/json")
+
+		var p map[string]string
+		err := json.NewDecoder(r.Body).Decode(&p)
+		assert.NoError(t, err)
+		assert.Equal(t, p["foo"], "bar")
+
+		data, err := json.Marshal(testServerResponse{Message: message})
+		assert.NoError(t, err)
+
+		_, err = w.Write(data)
+		assert.NoError(t, err)
+	}))
+	defer testServer.Close()
+
+	backend := GetBackendWithConfig(
+		APIBackend,
+		&BackendConfig{
+			EnableTelemetry:   Bool(true),
+			LeveledLogger:     debugLeveledLogger,
+			MaxNetworkRetries: Int64(0),
+			URL:               String(testServer.URL),
+		},
+	)
+
+	type myCreateParams struct {
+		Params `form:"*"`
+		Foo    string `form:"foo" json:"foo"`
+	}
+	params := &myCreateParams{
+		Foo: "bar",
+	}
+
+	var response testServerResponse
+	err := backend.Call(http.MethodPost, "/v2/hello", "sk_test_xyz", params, &response)
+
+	assert.NoError(t, err)
+	assert.Equal(t, message, response.Message)
+}
+
+// Test that a POST to a v2 endpoint works and is sent with an empty body
+// when params are nil
+func TestCall_V2PathPostNilParams(t *testing.T) {
+	type testServerResponse struct {
+		APIResource
+		Message string `json:"message"`
+	}
+
+	message := "Hello, client."
+
+	testServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		assert.Equal(t, r.Method, http.MethodPost)
+		assert.Equal(t, r.URL.Path, "/v2/hello")
+		assert.Equal(t, r.Header.Get("Content-Type"), "application/json")
+
+		body, err := ioutil.ReadAll(r.Body)
+		assert.NoError(t, err)
+		assert.Equal(t, body, []byte{})
+
+		data, err := json.Marshal(testServerResponse{Message: message})
+		assert.NoError(t, err)
+
+		_, err = w.Write(data)
+		assert.NoError(t, err)
+	}))
+	defer testServer.Close()
+
+	backend := GetBackendWithConfig(
+		APIBackend,
+		&BackendConfig{
+			EnableTelemetry:   Bool(true),
+			LeveledLogger:     debugLeveledLogger,
+			MaxNetworkRetries: Int64(0),
+			URL:               String(testServer.URL),
+		},
+	)
+
+	var response testServerResponse
+	err := backend.Call(http.MethodPost, "/v2/hello", "sk_test_xyz", nil, &response)
+
+	assert.NoError(t, err)
+	assert.Equal(t, message, response.Message)
+}
+
 func TestDo_Redaction(t *testing.T) {
 	type testServerResponse struct {
 		Error *Error `json:"error"`
@@ -650,7 +795,7 @@ func TestDo_Redaction(t *testing.T) {
 
 	request, err := backend.NewRequest(
 		http.MethodGet,
-		"/hello",
+		"/v1/hello",
 		"sk_test_123",
 		"application/x-www-form-urlencoded",
 		nil,
@@ -696,7 +841,7 @@ func TestDoStreaming(t *testing.T) {
 	response := streamingResource{}
 	err := backend.CallStreaming(
 		http.MethodGet,
-		"/pdf",
+		"/v1/pdf",
 		"sk_test_123",
 		nil,
 		&response,
@@ -745,7 +890,7 @@ func TestDoStreaming_ParsableError(t *testing.T) {
 	response := streamingResource{}
 	err := backend.CallStreaming(
 		http.MethodGet,
-		"/pdf",
+		"/v1/pdf",
 		"sk_test_123",
 		nil,
 		&response,
@@ -788,7 +933,7 @@ func TestDoStreaming_UnparsableError(t *testing.T) {
 	response := streamingResource{}
 	err := backend.CallStreaming(
 		http.MethodGet,
-		"/pdf",
+		"/v1/pdf",
 		"sk_test_123",
 		nil,
 		&response,
diff --git a/testhelpers/testclock/client.go b/testhelpers/testclock/client.go
index 598e1f67..09107778 100644
--- a/testhelpers/testclock/client.go
+++ b/testhelpers/testclock/client.go
@@ -82,7 +82,7 @@ func (c Client) List(listParams *stripe.TestHelpersTestClockListParams) *Iter {
 	return &Iter{
 		Iter: stripe.GetIter(listParams, func(p *stripe.Params, b *form.Values) ([]interface{}, stripe.ListContainer, error) {
 			list := &stripe.TestHelpersTestClockList{}
-			err := c.B.CallRaw(http.MethodGet, "/v1/test_helpers/test_clocks", c.Key, b, p, list)
+			err := c.B.CallRaw(http.MethodGet, "/v1/test_helpers/test_clocks", c.Key, []byte(b.Encode()), p, list)
 
 			ret := make([]interface{}, len(list.Data))
 			for i, v := range list.Data {